From 55412079757fd5488b426e55e96f981a14db1cf9 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 11 Dec 2014 11:37:20 -0500 Subject: [PATCH 01/29] Add lifetime elision information to the ownership guide. Fixes #19662. --- src/doc/guide-ownership.md | 80 +++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/src/doc/guide-ownership.md b/src/doc/guide-ownership.md index aebafebf98ed3..855a3534a5915 100644 --- a/src/doc/guide-ownership.md +++ b/src/doc/guide-ownership.md @@ -230,8 +230,9 @@ fn add_one(num: &int) -> int { ``` Rust has a feature called 'lifetime elision,' which allows you to not write -lifetime annotations in certain circumstances. This is one of them. Without -eliding the lifetimes, `add_one` looks like this: +lifetime annotations in certain circumstances. This is one of them. We will +cover the others later. Without eliding the lifetimes, `add_one` looks like +this: ```rust fn add_one<'a>(num: &'a int) -> int { @@ -449,6 +450,81 @@ This is the simplest kind of multiple ownership possible. For example, there's also `Arc`, which uses more expensive atomic instructions to be the thread-safe counterpart of `Rc`. +## Lifetime Elision + +Earlier, we mentioned 'lifetime elision,' a feature of Rust which allows you to +not write lifetime annotations in certain circumstances. All references have a +lifetime, and so if you elide a lifetime (like `&T` instead of `&'a T`), Rust +will do three things to determine what those lifetimes should be. + +When talking about lifetime elision, we use the term 'input lifetime' and +'output lifetime'. An 'input liftime' is a lifetime associated with a parameter +of a function, and an 'output lifetime' is a lifetime associated with the return +value of a function. For example, this function has an input lifetime: + +``` +fn foo<'a>(bar: &'a str) +``` + +This one has an output lifetime: + +``` +fn foo<'a>() -> &'a str +``` + +This one has both: + +``` +fn foo<'a>(bar: &'a str) -> &'a str +``` + +Here are the three rules: + +* Each elided lifetime in a function's arguments becomes a distinct lifetime + parameter. + +* If there is exactly one input lifetime, elided or not, that lifetime is + assigned to all elided lifetimes in the return values of that function.. + +* If there are multiple input lifetimes, but one of them is `&self` or `&mut + self`, the lifetime of `self` is assigned to all elided output lifetimes. + +Otherwise, it is an error to elide an output lifetime. + +### Examples + +Here are some examples of functions with elided lifetimes, and the version of +what the elided lifetimes are expand to: + +```{rust,ignore} +fn print(s: &str); // elided +fn print<'a>(s: &'a str); // expanded + +fn debug(lvl: uint, s: &str); // elided +fn debug<'a>(lvl: uint, s: &'a str); // expanded + +// In the preceeding example, `lvl` doesn't need a lifetime because it's not a +// reference (`&`). Only things relating to references (such as a `struct` +// which contains a reference) need lifetimes. + +fn substr(s: &str, until: uint) -> &str; // elided +fn substr<'a>(s: &'a str, until: uint) -> &'a str; // expanded + +fn get_str() -> &str; // ILLEGAL, no inputs + +fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs + +fn get_mut(&mut self) -> &mut T; // elided +fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded + +fn args(&mut self, args: &[T]) -> &mut Command // elided +fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded + +fn new(buf: &mut [u8]) -> BufWriter; // elided +fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded + +``` + # Related Resources Coming Soon. From 9f244dc97a1ee0340d53de5faedb5a170fa8e6f2 Mon Sep 17 00:00:00 2001 From: Barosl Lee Date: Sat, 13 Dec 2014 23:54:06 +0900 Subject: [PATCH 02/29] Minor fix for the Rust language FAQ extra library -> standard library --- src/doc/complement-lang-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index 9e73863239fbc..a9a9e0858ec6b 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -17,7 +17,7 @@ Some examples that demonstrate different aspects of the language: * [sprocketnes], an NES emulator with no GC, using modern Rust conventions * The language's general-purpose [hash] function, SipHash-2-4. Bit twiddling, OO, macros * The standard library's [HashMap], a sendable hash map in an OO style -* The extra library's [json] module. Enums and pattern matching +* The standard library's [json] module. Enums and pattern matching [sprocketnes]: https://github.com/pcwalton/sprocketnes [hash]: https://github.com/rust-lang/rust/blob/master/src/libstd/hash/mod.rs From 739f74bb156538880464b6e776048d02bf4c6adb Mon Sep 17 00:00:00 2001 From: Barosl Lee Date: Sat, 20 Dec 2014 03:56:47 +0900 Subject: [PATCH 03/29] Make the line numbers of the source code clickable --- src/librustdoc/html/render.rs | 4 ++-- src/librustdoc/html/static/main.css | 16 ++++++++++--- src/librustdoc/html/static/main.js | 37 ++++++++++++++++++++++++++--- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 304dbe201e8fd..bbd76adb5766b 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2249,9 +2249,9 @@ impl<'a> fmt::Show for Source<'a> { cols += 1; tmp /= 10; } - try!(write!(fmt, "
"));
+        try!(write!(fmt, "
"));
         for i in range(1, lines + 1) {
-            try!(write!(fmt, "{0:1$}\n", i, cols));
+            try!(write!(fmt, "{0:1$}\n", i, cols));
         }
         try!(write!(fmt, "
")); try!(write!(fmt, "{}", highlight::highlight(s.as_slice(), None, None))); diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index dc62273364c20..c0d3e2c19eb51 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -157,6 +157,7 @@ nav.sub { left: 0; top: 0; min-height: 100%; + z-index: -1; } .content, nav { max-width: 960px; } @@ -217,10 +218,18 @@ nav.sub { overflow: auto; padding-left: 0; } -.content pre.line-numbers { float: left; border: none; } -.line-numbers span { color: #c67e2d; } +.content pre.line-numbers { + float: left; + border: none; + + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.line-numbers span { color: #c67e2d; cursor: pointer; } .line-numbers .line-highlighted { - background-color: #f6fdb0; + background-color: #f6fdb0 !important; } .content .highlighted { @@ -465,6 +474,7 @@ h1 .stability { .summary.Unmarked { background-color: #BBBBBB; } :target { background: #FDFFD3; } +.line-numbers :target { background-color: transparent; } /* Code highlighting */ pre.rust .kw { color: #8959A8; } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 978af31cdc689..2d575c226c5d0 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -50,7 +50,7 @@ resizeShortBlocks(); $(window).on('resize', resizeShortBlocks); - function highlightSourceLines() { + function highlightSourceLines(ev) { var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/); if (match) { from = parseInt(match[1], 10); @@ -59,14 +59,14 @@ if ($('#' + from).length === 0) { return; } - $('#' + from)[0].scrollIntoView(); + if (ev === null) $('#' + from)[0].scrollIntoView(); $('.line-numbers span').removeClass('line-highlighted'); for (i = from; i <= to; ++i) { $('#' + i).addClass('line-highlighted'); } } } - highlightSourceLines(); + highlightSourceLines(null); $(window).on('hashchange', highlightSourceLines); $(document).on('keyup', function(e) { @@ -778,4 +778,35 @@ $("#main > .docblock").before(wrapper); }); + $('pre.line-numbers').on('click', 'span', function() { + var prev_id = 0; + + function set_fragment(name) { + if (history.replaceState) { + history.replaceState(null, null, '#' + name); + $(window).trigger('hashchange'); + } else { + location.replace('#' + name); + } + } + + return function(ev) { + var cur_id = parseInt(ev.target.id); + + if (ev.shiftKey && prev_id) { + if (prev_id > cur_id) { + var tmp = prev_id; + prev_id = cur_id; + cur_id = tmp; + } + + set_fragment(prev_id + '-' + cur_id); + } else { + prev_id = cur_id; + + set_fragment(cur_id); + } + }; + }()); + }()); From 9554794d22840b5077aa4605fa49a587d3e018b6 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Sat, 27 Dec 2014 18:19:27 +0900 Subject: [PATCH 04/29] Add unstable_options method --- src/librustc/session/mod.rs | 3 +++ src/librustc_driver/lib.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 37bdd1673e9ca..c120ac53b7811 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -202,6 +202,9 @@ impl Session { pub fn show_span(&self) -> bool { self.debugging_opt(config::SHOW_SPAN) } + pub fn unstable_options(&self) -> bool { + self.debugging_opt(config::UNSTABLE_OPTIONS) + } pub fn sysroot<'a>(&'a self) -> &'a Path { match self.opts.maybe_sysroot { Some (ref sysroot) => sysroot, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index e2791aff14e49..5cd87a1e4c080 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -143,7 +143,7 @@ fn run_compiler(args: &[String]) { pretty::parse_pretty(&sess, a.as_slice(), false) }); let pretty = if pretty.is_none() && - sess.debugging_opt(config::UNSTABLE_OPTIONS) { + sess.unstable_options() { matches.opt_str("xpretty").map(|a| { // extended with unstable pretty-print variants pretty::parse_pretty(&sess, a.as_slice(), true) From d4da75892219ee8fed5fc8801a37ffe82520083d Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Sat, 27 Dec 2014 19:43:14 +0900 Subject: [PATCH 05/29] Use -Z unstable-options for span debugger --- src/librustc/session/config.rs | 6 ++++-- src/librustc/session/mod.rs | 3 --- src/librustc_driver/driver.rs | 4 ++-- src/librustc_driver/lib.rs | 6 +++++- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 6629f6620d484..61676407991fc 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -105,6 +105,7 @@ pub struct Options { pub prints: Vec, pub cg: CodegenOptions, pub color: ColorConfig, + pub show_span: Option, pub externs: HashMap>, pub crate_name: Option, /// An optional name to use as the crate for std during std injection, @@ -211,6 +212,7 @@ pub fn basic_options() -> Options { prints: Vec::new(), cg: basic_codegen_options(), color: Auto, + show_span: None, externs: HashMap::new(), crate_name: None, alt_std_name: None, @@ -259,7 +261,6 @@ debugging_opts! { BORROWCK_STATS, NO_LANDING_PADS, DEBUG_LLVM, - SHOW_SPAN, COUNT_TYPE_SIZES, META_STATS, GC, @@ -298,7 +299,6 @@ pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> { ("no-landing-pads", "omit landing pads for unwinding", NO_LANDING_PADS), ("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM), - ("show-span", "show spans for compiler debugging", SHOW_SPAN), ("count-type-sizes", "count the sizes of aggregate types", COUNT_TYPE_SIZES), ("meta-stats", "gather metadata statistics", META_STATS), @@ -820,6 +820,7 @@ pub fn rustc_optgroups() -> Vec { `flowgraph=` (graphviz formatted flowgraph for node), or `everybody_loops` (all function bodies replaced with `loop {}`).", "TYPE"), + opt::opt_u("", "show-span", "Show spans for compiler debugging", "expr|pat|ty"), opt::flagopt("", "dep-info", "Output dependency info to after compiling, \ in a format suitable for use by Makefiles", "FILENAME"), @@ -1122,6 +1123,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { prints: prints, cg: cg, color: color, + show_span: None, externs: externs, crate_name: crate_name, alt_std_name: None, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index c120ac53b7811..9a6275401adc8 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -199,9 +199,6 @@ impl Session { pub fn no_landing_pads(&self) -> bool { self.debugging_opt(config::NO_LANDING_PADS) } - pub fn show_span(&self) -> bool { - self.debugging_opt(config::SHOW_SPAN) - } pub fn unstable_options(&self) -> bool { self.debugging_opt(config::UNSTABLE_OPTIONS) } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 20bb9c2f4fd1c..69e439c1bbe27 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -138,7 +138,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) krate.encode(&mut json).unwrap(); } - if sess.show_span() { + if sess.opts.show_span.is_some() { syntax::show_span::run(sess.diagnostic(), &krate); } @@ -542,7 +542,7 @@ pub fn stop_after_phase_1(sess: &Session) -> bool { debug!("invoked with --parse-only, returning early from compile_input"); return true; } - if sess.show_span() { + if sess.opts.show_span.is_some() { return true; } return sess.opts.debugging_opts & config::AST_JSON_NOEXPAND != 0; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 5cd87a1e4c080..98d2b5eb67d3c 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -132,7 +132,7 @@ fn run_compiler(args: &[String]) { _ => early_error("multiple input filenames provided") }; - let sess = build_session(sopts, input_file_path, descriptions); + let mut sess = build_session(sopts, input_file_path, descriptions); let cfg = config::build_configuration(&sess); if print_crate_info(&sess, Some(&input), &odir, &ofile) { return @@ -160,6 +160,10 @@ fn run_compiler(args: &[String]) { None => {/* continue */ } } + if sess.unstable_options() { + sess.opts.show_span = matches.opt_str("show-span"); + } + let r = matches.opt_strs("Z"); if r.contains(&("ls".to_string())) { match input { From 20fa7cbfc0b5143f6c88e288772fc0f65610c2ec Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 15 Dec 2014 13:51:04 -0500 Subject: [PATCH 06/29] Add header to optimizations section --- src/doc/guide-testing.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/guide-testing.md b/src/doc/guide-testing.md index 682c89fcc53fc..60ce71dac8454 100644 --- a/src/doc/guide-testing.md +++ b/src/doc/guide-testing.md @@ -503,6 +503,8 @@ Advice on writing benchmarks: * Make the code in the `iter` loop do something simple, to assist in pinpointing performance improvements (or regressions) +## Gotcha: optimizations + There's another tricky part to writing benchmarks: benchmarks compiled with optimizations activated can be dramatically changed by the optimizer so that the benchmark is no longer benchmarking what one expects. For example, the From cd85f0a56a790f24bb1c1928fbc37c9d24dd2937 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 15 Dec 2014 13:53:14 -0500 Subject: [PATCH 07/29] restore paragraph Fixes #19861 --- src/doc/guide-testing.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/doc/guide-testing.md b/src/doc/guide-testing.md index 60ce71dac8454..8d113bb931a09 100644 --- a/src/doc/guide-testing.md +++ b/src/doc/guide-testing.md @@ -556,8 +556,12 @@ extern crate test; # fn main() { # struct X; impl X { fn iter(&self, _: || -> T) {} } let b = X; b.iter(|| { - test::black_box(range(0u, 1000).fold(0, |old, new| old ^ new)); -}); + let mut n = 1000_u32; + + test::black_box(&mut n); // pretend to modify `n` + + range(0, n).fold(0, |a, b| a ^ b) +}) # } ``` @@ -573,3 +577,6 @@ test bench_xor_1000_ints ... bench: 1 ns/iter (+/- 0) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured ``` + +However, the optimizer can still modify a testcase in an undesirable manner +even when using either of the above. From 98aeac2930dfd64ef1cb52c3a20e1f3609feee8e Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Sat, 27 Dec 2014 21:00:48 +0900 Subject: [PATCH 08/29] Extend span debugger --- src/librustc_driver/driver.rs | 4 +-- src/libsyntax/show_span.rs | 52 +++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 69e439c1bbe27..5e563ae9d6dfa 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -138,8 +138,8 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) krate.encode(&mut json).unwrap(); } - if sess.opts.show_span.is_some() { - syntax::show_span::run(sess.diagnostic(), &krate); + if let Some(ref s) = sess.opts.show_span { + syntax::show_span::run(sess.diagnostic(), s.as_slice(), &krate); } krate diff --git a/src/libsyntax/show_span.rs b/src/libsyntax/show_span.rs index 354ba854b101a..51d655ec0f2c5 100644 --- a/src/libsyntax/show_span.rs +++ b/src/libsyntax/show_span.rs @@ -13,27 +13,73 @@ //! This module shows spans for all expressions in the crate //! to help with compiler debugging. +use std::str::FromStr; + use ast; use diagnostic; use visit; use visit::Visitor; +enum Mode { + Expression, + Pattern, + Type, +} + +impl FromStr for Mode { + fn from_str(s: &str) -> Option { + let mode = match s { + "expr" => Mode::Expression, + "pat" => Mode::Pattern, + "ty" => Mode::Type, + _ => return None + }; + Some(mode) + } +} + struct ShowSpanVisitor<'a> { span_diagnostic: &'a diagnostic::SpanHandler, + mode: Mode, } impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> { fn visit_expr(&mut self, e: &ast::Expr) { - self.span_diagnostic.span_note(e.span, "expression"); + if let Mode::Expression = self.mode { + self.span_diagnostic.span_note(e.span, "expression"); + } visit::walk_expr(self, e); } + fn visit_pat(&mut self, p: &ast::Pat) { + if let Mode::Pattern = self.mode { + self.span_diagnostic.span_note(p.span, "pattern"); + } + visit::walk_pat(self, p); + } + + fn visit_ty(&mut self, t: &ast::Ty) { + if let Mode::Type = self.mode { + self.span_diagnostic.span_note(t.span, "type"); + } + visit::walk_ty(self, t); + } + fn visit_mac(&mut self, macro: &ast::Mac) { visit::walk_mac(self, macro); } } -pub fn run(span_diagnostic: &diagnostic::SpanHandler, krate: &ast::Crate) { - let mut v = ShowSpanVisitor { span_diagnostic: span_diagnostic }; +pub fn run(span_diagnostic: &diagnostic::SpanHandler, + mode: &str, + krate: &ast::Crate) { + let mode = match mode.parse() { + Some(mode) => mode, + None => return + }; + let mut v = ShowSpanVisitor { + span_diagnostic: span_diagnostic, + mode: mode, + }; visit::walk_crate(&mut v, krate); } From 5cf72ff8988243814aed3f384ea272e2c3d85ee2 Mon Sep 17 00:00:00 2001 From: P1start Date: Sun, 21 Dec 2014 19:03:31 +1300 Subject: [PATCH 09/29] Parse arbitrary operators after expr-like macro invocations in statement position Closes #20093. --- src/libsyntax/parse/parser.rs | 15 ++++--- .../run-pass/parse-complex-macro-invoc-op.rs | 43 +++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 src/test/run-pass/parse-complex-macro-invoc-op.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2f43661eebeba..3acb74485f5ef 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2995,14 +2995,17 @@ impl<'a> Parser<'a> { /// actually, this seems to be the main entry point for /// parsing an arbitrary expression. pub fn parse_assign_expr(&mut self) -> P { - let lo = self.span.lo; let lhs = self.parse_binops(); + self.parse_assign_expr_with(lhs) + } + + pub fn parse_assign_expr_with(&mut self, lhs: P) -> P { let restrictions = self.restrictions & RESTRICTION_NO_STRUCT_LITERAL; match self.token { token::Eq => { self.bump(); let rhs = self.parse_expr_res(restrictions); - self.mk_expr(lo, rhs.span.hi, ExprAssign(lhs, rhs)) + self.mk_expr(lhs.span.lo, rhs.span.hi, ExprAssign(lhs, rhs)) } token::BinOpEq(op) => { self.bump(); @@ -3020,8 +3023,9 @@ impl<'a> Parser<'a> { token::Shr => BiShr }; let rhs_span = rhs.span; + let span = lhs.span; let assign_op = self.mk_assign_op(aop, lhs, rhs); - self.mk_expr(lo, rhs_span.hi, assign_op) + self.mk_expr(span.lo, rhs_span.hi, assign_op) } _ => { lhs @@ -3919,8 +3923,9 @@ impl<'a> Parser<'a> { let e = self.mk_mac_expr(span.lo, span.hi, macro.and_then(|m| m.node)); - let e = - self.parse_dot_or_call_expr_with(e); + let e = self.parse_dot_or_call_expr_with(e); + let e = self.parse_more_binops(e, 0); + let e = self.parse_assign_expr_with(e); self.handle_expression_like_statement( e, ast::DUMMY_NODE_ID, diff --git a/src/test/run-pass/parse-complex-macro-invoc-op.rs b/src/test/run-pass/parse-complex-macro-invoc-op.rs new file mode 100644 index 0000000000000..e9ec624c13edf --- /dev/null +++ b/src/test/run-pass/parse-complex-macro-invoc-op.rs @@ -0,0 +1,43 @@ +// 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. + +// Test parsing binary operators after macro invocations. + +#![feature(macro_rules)] + +macro_rules! id { + ($e: expr) => { $e } +} + +fn foo() { + id!(1i) + 1; + id![1i] - 1; + id!(1i) * 1; + id![1i] / 1; + id!(1i) % 1; + + id!(1i) & 1; + id![1i] | 1; + id!(1i) ^ 1; + + let mut x = 1i; + id![x] = 2; + id!(x) += 1; + + id!(1f64).clone(); + + id!([1i, 2, 3])[1]; + id![drop](1i); + + id!(true) && true; + id![true] || true; +} + +fn main() {} From 5b0bebf6b492332ccb56de4308992174d43731b6 Mon Sep 17 00:00:00 2001 From: Travis Watkins Date: Sat, 3 Jan 2015 02:49:42 -0600 Subject: [PATCH 10/29] Return passed value from black_box By returning the passed value black_box can be used on data being passed to a function being benchmarked. This ensures the compiler does not optimize the function for the input which could result in the entire function being optimized away. --- src/libtest/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index b2d3611fc64fc..7685bba7f7346 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -1332,10 +1332,11 @@ impl MetricMap { /// elimination. /// /// This function is a no-op, and does not even read from `dummy`. -pub fn black_box(dummy: T) { +pub fn black_box(dummy: T) -> T { // we need to "use" the argument in some way LLVM can't // introspect. unsafe {asm!("" : : "r"(&dummy))} + dummy } From 399579785cda1bceb1a0b0848dc1d713d948166d Mon Sep 17 00:00:00 2001 From: Sean T Allen Date: Sat, 3 Jan 2015 12:26:03 -0500 Subject: [PATCH 11/29] Minor documentation edit. Number of rustc calls would depending on various circumstances. Two is misleading. --- src/doc/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index 55465651cfb4b..ed49cc5bb39ce 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -354,7 +354,7 @@ Hello, world! Bam! We build our project with `cargo build`, and run it with `./target/hello_world`. This hasn't bought us a whole lot over our simple use of `rustc`, but think about the future: when our project has more than one -file, we would need to call `rustc` twice, and pass it a bunch of options to +file, we would need to call `rustc` more than once, and pass it a bunch of options to tell it to build everything together. With Cargo, as our project grows, we can just `cargo build` and it'll work the right way. From 053698686550852ffa6be622697baf314d2bb4b4 Mon Sep 17 00:00:00 2001 From: Sean T Allen Date: Sat, 3 Jan 2015 13:00:38 -0500 Subject: [PATCH 12/29] Minor documentation edit. A tuple could be more made up of more than 2 values. Update guide to reflect. --- src/doc/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index ed49cc5bb39ce..cde1167982ded 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -978,7 +978,7 @@ fn main() { ``` Even though Rust functions can only return one value, a tuple _is_ one value, -that happens to be made up of two. You can also see in this example how you +that happens to be made up of more than one value. You can also see in this example how you can destructure a pattern returned by a function, as well. Tuples are a very simple data structure, and so are not often what you want. From 149833d4b4d72ca0267429b237a588efe36e348d Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 3 Jan 2015 12:34:48 -0800 Subject: [PATCH 13/29] Update rust-installer. Fixes #20479 --- src/rust-installer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust-installer b/src/rust-installer index 3a37981744a5a..b5ac4cd44321d 160000 --- a/src/rust-installer +++ b/src/rust-installer @@ -1 +1 @@ -Subproject commit 3a37981744a5af2433fed551f742465c78c9af7f +Subproject commit b5ac4cd44321da10dfd70f070dbc9094ca3f92ff From 8cebb1f64498508e1fc940d885ad05d7a2fb4089 Mon Sep 17 00:00:00 2001 From: Chase Southwood Date: Sun, 4 Jan 2015 00:09:18 -0600 Subject: [PATCH 14/29] Rename `raw_pointer_deriving` lint to `raw_pointer_derive` Due to the `#[deriving]` -> `#[derive]` switch. --- src/librustc/lint/builtin.rs | 22 +++++++++---------- src/librustc/lint/context.rs | 3 ++- ...ptr-deriving.rs => lint-raw-ptr-derive.rs} | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) rename src/test/compile-fail/{lint-raw-ptr-deriving.rs => lint-raw-ptr-derive.rs} (97%) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 53249c724627e..e44e3154d3df1 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -550,20 +550,20 @@ impl LintPass for BoxPointers { } declare_lint! { - RAW_POINTER_DERIVING, + RAW_POINTER_DERIVE, Warn, "uses of #[derive] with raw pointers are rarely correct" } -struct RawPtrDerivingVisitor<'a, 'tcx: 'a> { +struct RawPtrDeriveVisitor<'a, 'tcx: 'a> { cx: &'a Context<'a, 'tcx> } -impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDerivingVisitor<'a, 'tcx> { +impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDeriveVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &ast::Ty) { static MSG: &'static str = "use of `#[derive]` with a raw pointer"; if let ast::TyPtr(..) = ty.node { - self.cx.span_lint(RAW_POINTER_DERIVING, ty.span, MSG); + self.cx.span_lint(RAW_POINTER_DERIVE, ty.span, MSG); } visit::walk_ty(self, ty); } @@ -572,21 +572,21 @@ impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDerivingVisitor<'a, 'tcx> { fn visit_block(&mut self, _: &ast::Block) {} } -pub struct RawPointerDeriving { +pub struct RawPointerDerive { checked_raw_pointers: NodeSet, } -impl RawPointerDeriving { - pub fn new() -> RawPointerDeriving { - RawPointerDeriving { +impl RawPointerDerive { + pub fn new() -> RawPointerDerive { + RawPointerDerive { checked_raw_pointers: NodeSet::new(), } } } -impl LintPass for RawPointerDeriving { +impl LintPass for RawPointerDerive { fn get_lints(&self) -> LintArray { - lint_array!(RAW_POINTER_DERIVING) + lint_array!(RAW_POINTER_DERIVE) } fn check_item(&mut self, cx: &Context, item: &ast::Item) { @@ -611,7 +611,7 @@ impl LintPass for RawPointerDeriving { if !self.checked_raw_pointers.insert(item.id) { return } match item.node { ast::ItemStruct(..) | ast::ItemEnum(..) => { - let mut visitor = RawPtrDerivingVisitor { cx: cx }; + let mut visitor = RawPtrDeriveVisitor { cx: cx }; visit::walk_item(&mut visitor, &*item); } _ => {} diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index ffae485364a86..9cf4ae9d467b0 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -208,7 +208,7 @@ impl LintStore { add_builtin_with_new!(sess, TypeLimits, - RawPointerDeriving, + RawPointerDerive, MissingDoc, ); @@ -247,6 +247,7 @@ impl LintStore { self.register_renamed("unknown_crate_type", "unknown_crate_types"); self.register_renamed("variant_size_difference", "variant_size_differences"); self.register_renamed("transmute_fat_ptr", "fat_ptr_transmutes"); + self.register_renamed("raw_pointer_deriving", "raw_pointer_derive"); } diff --git a/src/test/compile-fail/lint-raw-ptr-deriving.rs b/src/test/compile-fail/lint-raw-ptr-derive.rs similarity index 97% rename from src/test/compile-fail/lint-raw-ptr-deriving.rs rename to src/test/compile-fail/lint-raw-ptr-derive.rs index 6fe8862d77e58..3198e782df893 100644 --- a/src/test/compile-fail/lint-raw-ptr-deriving.rs +++ b/src/test/compile-fail/lint-raw-ptr-derive.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(dead_code)] -#![deny(raw_pointer_deriving)] +#![deny(raw_pointer_derive)] #[derive(Clone)] struct Foo { From 56f3f83cfb0839c6dc80186ad74852fd6500918e Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Fri, 2 Jan 2015 04:02:50 -0800 Subject: [PATCH 15/29] Fix the parsing of where-clauses for structs --- src/libsyntax/parse/parser.rs | 24 +++++++++++++++++++++--- src/test/run-pass/issue-17904.rs | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/issue-17904.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 37ac86a33242e..570ef67bbccfd 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4875,11 +4875,26 @@ impl<'a> Parser<'a> { self.span_err(ty.span, "`virtual` structs have been removed from the language"); } - self.parse_where_clause(&mut generics); - let mut fields: Vec; let is_tuple_like; + // There is a special case worth noting here, as reported in issue #17904. + // If we are parsing a tuple struct it is the case that the where clause + // should follow the field list. Like so: + // + // struct Foo(T) where T: Copy; + // + // If we are parsing a normal record-style struct it is the case + // that the where clause comes before the body, and after the generics. + // So if we look ahead and see a brace or a where-clause we begin + // parsing a record style struct. + // + // Otherwise if we look ahead and see a paren we parse a tuple-style + // struct. + + // Will parse the where-clause if it precedes the brace. + self.parse_where_clause(&mut generics); + if self.eat(&token::OpenDelim(token::Brace)) { // It's a record-like struct. is_tuple_like = false; @@ -4916,8 +4931,11 @@ impl<'a> Parser<'a> { written as `struct {};`", token::get_ident(class_name))[]); } + self.parse_where_clause(&mut generics); self.expect(&token::Semi); - } else if self.eat(&token::Semi) { + } else if self.token.is_keyword(keywords::Where) || self.eat(&token::Semi) { + // We can find a where clause here. + self.parse_where_clause(&mut generics); // It's a unit-like struct. is_tuple_like = true; fields = Vec::new(); diff --git a/src/test/run-pass/issue-17904.rs b/src/test/run-pass/issue-17904.rs new file mode 100644 index 0000000000000..c2976378ddad8 --- /dev/null +++ b/src/test/run-pass/issue-17904.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. + +// Tests that type assignability is used to search for instances when +// making method calls, but only if there aren't any matches without +// it. + +struct Foo where T: Copy; +struct Bar(T) where T: Copy; +struct Bleh(T, U) where T: Copy, U: Sized; +struct Baz where T: Copy { + field: T +} + +fn main() {} From e723fe07783cd9b797c9f1456d359879bba44907 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 4 Jan 2015 14:58:08 +0200 Subject: [PATCH 16/29] Do not use entropy during gen_weighted_bool(1) 1 in 1 chance to return true always results in true. --- src/librand/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 0f8dbc78cde32..18f508e816f2b 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -243,7 +243,7 @@ pub trait Rng : Sized { /// println!("{}", rng.gen_weighted_bool(3)); /// ``` fn gen_weighted_bool(&mut self, n: uint) -> bool { - n == 0 || self.gen_range(0, n) == 0 + n <= 1 || self.gen_range(0, n) == 0 } /// Return an iterator of random characters from the set A-Z,a-z,0-9. From 9b820d0d634483e5400b1da52340a0606a32c84a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jan 2015 05:22:59 -0500 Subject: [PATCH 17/29] Correct the subtyping relations created by the pattern typechecking code. Previously we were creating a subtyping relation in the wrong direction. We now just unify types, which is stronger than necessary but turns out fine. Fixes #19552. Fixes #19997. --- src/librustc_typeck/check/_match.rs | 108 ++++++++++++++++-- .../regions-pattern-typing-issue-19552.rs | 18 +++ .../regions-pattern-typing-issue-19997.rs | 20 ++++ .../regions-reassign-let-bound-pointer.rs | 23 ++++ .../regions-reassign-match-bound-pointer.rs | 26 +++++ ...ions-on-closures-to-inference-variables.rs | 65 +++++++++++ 6 files changed, 251 insertions(+), 9 deletions(-) create mode 100644 src/test/compile-fail/regions-pattern-typing-issue-19552.rs create mode 100644 src/test/compile-fail/regions-pattern-typing-issue-19997.rs create mode 100644 src/test/run-pass/regions-reassign-let-bound-pointer.rs create mode 100644 src/test/run-pass/regions-reassign-match-bound-pointer.rs create mode 100644 src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 7c431b4fc0bd0..d0fd5732f233d 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -46,6 +46,19 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, check_expr(fcx, &**lt); let expr_ty = fcx.expr_ty(&**lt); fcx.write_ty(pat.id, expr_ty); + + // somewhat surprising: in this case, the subtyping + // relation goes the opposite way as the other + // cases. Actually what we really want is not a subtyping + // relation at all but rather that there exists a LUB (so + // that they can be compared). However, in practice, + // constants are always scalars or strings. For scalars + // subtyping is irrelevant, and for strings `expr_ty` is + // type is `&'static str`, so if we say that + // + // &'static str <: expected + // + // that's equivalent to there existing a LUB. demand::suptype(fcx, pat.span, expected, expr_ty); } ast::PatRange(ref begin, ref end) => { @@ -54,10 +67,16 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let lhs_ty = fcx.expr_ty(&**begin); let rhs_ty = fcx.expr_ty(&**end); - if require_same_types( - tcx, Some(fcx.infcx()), false, pat.span, lhs_ty, rhs_ty, - || "mismatched types in range".to_string()) - && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(rhs_ty)) { + + let lhs_eq_rhs = + require_same_types( + tcx, Some(fcx.infcx()), false, pat.span, lhs_ty, rhs_ty, + || "mismatched types in range".to_string()); + + let numeric_or_char = + lhs_eq_rhs && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(lhs_ty)); + + if numeric_or_char { match valid_range_bounds(fcx.ccx, &**begin, &**end) { Some(false) => { span_err!(tcx.sess, begin.span, E0030, @@ -75,6 +94,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } fcx.write_ty(pat.id, lhs_ty); + + // subtyping doens't matter here, as the value is some kind of scalar demand::eqtype(fcx, pat.span, expected, lhs_ty); } ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => { @@ -89,20 +110,29 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ast::BindByRef(mutbl) => { // if the binding is like // ref x | ref const x | ref mut x - // then the type of x is &M T where M is the mutability - // and T is the expected type + // then `x` is assigned a value of type `&M T` where M is the mutability + // and T is the expected type. let region_var = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); let mt = ty::mt { ty: expected, mutbl: mutbl }; let region_ty = ty::mk_rptr(tcx, tcx.mk_region(region_var), mt); + + // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is + // required. However, we use equality, which is stronger. See (*) for + // an explanation. demand::eqtype(fcx, pat.span, region_ty, typ); } // otherwise the type of x is the expected type T ast::BindByValue(_) => { + // As above, `T <: typeof(x)` is required but we + // use equality, see (*) below. demand::eqtype(fcx, pat.span, expected, typ); } } + fcx.write_ty(pat.id, typ); + // if there are multiple arms, make sure they all agree on + // what the type of the binding `x` ought to be let canon_id = pcx.map[path.node]; if canon_id != pat.id { let ct = fcx.local_ty(pat.span, canon_id); @@ -138,7 +168,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let uniq_ty = ty::mk_uniq(tcx, inner_ty); if check_dereferencable(pcx, pat.span, expected, &**inner) { - demand::suptype(fcx, pat.span, expected, uniq_ty); + // Here, `demand::subtype` is good enough, but I don't + // think any errors can be introduced by using + // `demand::eqtype`. + demand::eqtype(fcx, pat.span, expected, uniq_ty); fcx.write_ty(pat.id, uniq_ty); check_pat(pcx, &**inner, inner_ty); } else { @@ -158,7 +191,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let rptr_ty = ty::mk_rptr(tcx, tcx.mk_region(region), mt); if check_dereferencable(pcx, pat.span, expected, &**inner) { - demand::suptype(fcx, pat.span, expected, rptr_ty); + // `demand::subtype` would be good enough, but using + // `eqtype` turns out to be equally general. See (*) + // below for details. + demand::eqtype(fcx, pat.span, expected, rptr_ty); fcx.write_ty(pat.id, rptr_ty); check_pat(pcx, &**inner, inner_ty); } else { @@ -188,7 +224,11 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, }; fcx.write_ty(pat.id, pat_ty); - demand::suptype(fcx, pat.span, expected, pat_ty); + + // `demand::subtype` would be good enough, but using + // `eqtype` turns out to be equally general. See (*) + // below for details. + demand::eqtype(fcx, pat.span, expected, pat_ty); for elt in before.iter() { check_pat(pcx, &**elt, inner_ty); @@ -210,6 +250,56 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } ast::PatMac(_) => tcx.sess.bug("unexpanded macro") } + + + // (*) In most of the cases above (literals and constants being + // the exception), we relate types using strict equality, evewn + // though subtyping would be sufficient. There are a few reasons + // for this, some of which are fairly subtle and which cost me + // (nmatsakis) an hour or two debugging to remember, so I thought + // I'd write them down this time. + // + // 1. Most importantly, there is no loss of expressiveness + // here. What we are saying is that the type of `x` + // becomes *exactly* what is expected. This might seem + // like it will cause errors in a case like this: + // + // ``` + // fn foo<'x>(x: &'x int) { + // let a = 1; + // let mut z = x; + // z = &a; + // } + // ``` + // + // The reason we might get an error is that `z` might be + // assigned a type like `&'x int`, and then we would have + // a problem when we try to assign `&a` to `z`, because + // the lifetime of `&a` (i.e., the enclosing block) is + // shorter than `'x`. + // + // HOWEVER, this code works fine. The reason is that the + // expected type here is whatever type the user wrote, not + // the initializer's type. In this case the user wrote + // nothing, so we are going to create a type variable `Z`. + // Then we will assign the type of the initializer (`&'x + // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we + // will instantiate `Z` as a type `&'0 int` where `'0` is + // a fresh region variable, with the constraint that `'x : + // '0`. So basically we're all set. + // + // Note that there are two tests to check that this remains true + // (`regions-reassign-{match,let}-bound-pointer.rs`). + // + // 2. Things go horribly wrong if we use subtype. The reason for + // THIS is a fairly subtle case involving bound regions. See the + // `givens` field in `region_inference`, as well as the test + // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, + // for details. Short version is that we must sometimes detect + // relationships between specific region variables and regions + // bound in a closure signature, and that detection gets thrown + // off when we substitute fresh region variables here to enable + // subtyping. } pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, diff --git a/src/test/compile-fail/regions-pattern-typing-issue-19552.rs b/src/test/compile-fail/regions-pattern-typing-issue-19552.rs new file mode 100644 index 0000000000000..3f722c9433bb2 --- /dev/null +++ b/src/test/compile-fail/regions-pattern-typing-issue-19552.rs @@ -0,0 +1,18 @@ +// 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. + +fn assert_send(_t: T) {} + +fn main() { + let line = String::new(); + match [line.as_slice()] { //~ ERROR `line` does not live long enough + [ word ] => { assert_send(word); } + } +} diff --git a/src/test/compile-fail/regions-pattern-typing-issue-19997.rs b/src/test/compile-fail/regions-pattern-typing-issue-19997.rs new file mode 100644 index 0000000000000..da839d7217261 --- /dev/null +++ b/src/test/compile-fail/regions-pattern-typing-issue-19997.rs @@ -0,0 +1,20 @@ +// 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. + +fn main() { + let a0 = 0u8; + let f = 1u8; + let mut a1 = &a0; + match (&a1,) { + (&ref b0,) => { + a1 = &f; //~ ERROR cannot assign + } + } +} diff --git a/src/test/run-pass/regions-reassign-let-bound-pointer.rs b/src/test/run-pass/regions-reassign-let-bound-pointer.rs new file mode 100644 index 0000000000000..ecf79de622222 --- /dev/null +++ b/src/test/run-pass/regions-reassign-let-bound-pointer.rs @@ -0,0 +1,23 @@ +// 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. + +// Check that the type checker permits us to reassign `z` which +// started out with a longer lifetime and was reassigned to a shorter +// one (it should infer to be the intersection). + +fn foo(x: &int) { + let a = 1; + let mut z = x; + z = &a; +} + +pub fn main() { + foo(&1); +} diff --git a/src/test/run-pass/regions-reassign-match-bound-pointer.rs b/src/test/run-pass/regions-reassign-match-bound-pointer.rs new file mode 100644 index 0000000000000..18312b17339ce --- /dev/null +++ b/src/test/run-pass/regions-reassign-match-bound-pointer.rs @@ -0,0 +1,26 @@ +// 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. + +// Check that the type checker permits us to reassign `z` which +// started out with a longer lifetime and was reassigned to a shorter +// one (it should infer to be the intersection). + +fn foo(x: &int) { + let a = 1; + match x { + mut z => { + z = &a; + } + } +} + +pub fn main() { + foo(&1); +} diff --git a/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs new file mode 100644 index 0000000000000..aa0ed023da3e2 --- /dev/null +++ b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs @@ -0,0 +1,65 @@ +// 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. + +// Test that this fairly specialized, but also reasonable, pattern +// typechecks. The pattern involves regions bound in closures that +// wind up related to inference variables. +// +// NB. Changes to the region implementatiosn have broken this pattern +// a few times, but it happens to be used in the compiler so those +// changes were caught. However, those uses in the compiler could +// easily get changed or refactored away in the future. + +struct Ctxt<'tcx> { + x: &'tcx Vec +} + +struct Foo<'a,'tcx:'a> { + cx: &'a Ctxt<'tcx>, +} + +impl<'a,'tcx> Foo<'a,'tcx> { + fn bother(&mut self) -> int { + self.elaborate_bounds(|this| { + // (*) Here: type of `this` is `&'f0 Foo<&'f1, '_2>`, + // where `'f0` and `'f1` are fresh, free regions that + // result from the bound regions on the closure, and `'2` + // is a region inference variable created by the call. Due + // to the constraints on the type, we find that `'_2 : 'f1 + // + 'f2` must hold (and can be assumed by the callee). + // Region inference has to do some clever stuff to avoid + // inferring `'_2` to be `'static` in this case, because + // it is created outside the closure but then related to + // regions bound by the closure itself. See the + // `region_inference.rs` file (and the `givens` field, in + // particular) for more details. + this.foo() + }) + } + + fn foo(&mut self) -> int { + 22 + } + + fn elaborate_bounds( + &mut self, + mk_cand: for<'b>|this: &mut Foo<'b, 'tcx>| -> int) + -> int + { + mk_cand(self) + } +} + +fn main() { + let v = vec!(); + let cx = Ctxt { x: &v }; + let mut foo = Foo { cx: &cx }; + assert_eq!(foo.bother(), 22); // just so the code is not dead, basically +} From a17a7c9f7572685df59e287c48450ccb09e8313a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jan 2015 05:23:29 -0500 Subject: [PATCH 18/29] Miscellaneous reformatting and commenting. --- src/librustc_typeck/check/_match.rs | 19 +++++++++++-------- src/librustc_typeck/check/demand.rs | 13 ++++++------- src/librustc_typeck/check/mod.rs | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index d0fd5732f233d..7ff0e1758f526 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -30,7 +30,9 @@ use syntax::print::pprust; use syntax::ptr::P; pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, - pat: &ast::Pat, expected: Ty<'tcx>) { + pat: &ast::Pat, + expected: Ty<'tcx>) +{ let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; @@ -90,7 +92,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } } else { span_err!(tcx.sess, begin.span, E0029, - "only char and numeric types are allowed in range"); + "only char and numeric types are allowed in range"); } fcx.write_ty(pat.id, lhs_ty); @@ -154,8 +156,9 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, check_pat_struct(pcx, pat, path, fields.as_slice(), etc, expected); } ast::PatTup(ref elements) => { - let element_tys: Vec<_> = range(0, elements.len()).map(|_| fcx.infcx() - .next_ty_var()).collect(); + let element_tys: Vec<_> = + range(0, elements.len()).map(|_| fcx.infcx().next_ty_var()) + .collect(); let pat_ty = ty::mk_tup(tcx, element_tys.clone()); fcx.write_ty(pat.id, pat_ty); demand::eqtype(fcx, pat.span, expected, pat_ty); @@ -183,8 +186,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let inner_ty = fcx.infcx().next_ty_var(); let mutbl = - ty::deref(fcx.infcx().shallow_resolve(expected), true) - .map_or(ast::MutImmutable, |mt| mt.mutbl); + ty::deref(fcx.infcx().shallow_resolve(expected), true).map(|mt| mt.mutbl) + .unwrap_or(ast::MutImmutable); let mt = ty::mt { ty: inner_ty, mutbl: mutbl }; let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); @@ -217,8 +220,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); ty::mk_slice(tcx, tcx.mk_region(region), ty::mt { ty: inner_ty, - mutbl: ty::deref(expected_ty, true) - .map_or(ast::MutImmutable, |mt| mt.mutbl) + mutbl: ty::deref(expected_ty, true).map(|mt| mt.mutbl) + .unwrap_or(ast::MutImmutable) }) } }; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 9af9eaf75f5a5..565964012085a 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -18,14 +18,15 @@ use syntax::ast; use syntax::codemap::Span; use util::ppaux::Repr; -// Requires that the two types unify, and prints an error message if they -// don't. +// Requires that the two types unify, and prints an error message if +// they don't. pub fn suptype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, - expected: Ty<'tcx>, actual: Ty<'tcx>) { - suptype_with_fn(fcx, sp, false, expected, actual, + ty_expected: Ty<'tcx>, ty_actual: Ty<'tcx>) { + suptype_with_fn(fcx, sp, false, ty_expected, ty_actual, |sp, e, a, s| { fcx.report_mismatched_types(sp, e, a, s) }) } +/// As `suptype`, but call `handle_err` if unification for subtyping fails. pub fn suptype_with_fn<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, b_is_expected: bool, @@ -48,9 +49,7 @@ pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { match infer::mk_eqty(fcx.infcx(), false, infer::Misc(sp), actual, expected) { Ok(()) => { /* ok */ } - Err(ref err) => { - fcx.report_mismatched_types(sp, expected, actual, err); - } + Err(ref err) => { fcx.report_mismatched_types(sp, expected, actual, err); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 82525b71052d2..0a7c406e63172 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4683,7 +4683,7 @@ impl<'tcx> Repr<'tcx> for Expectation<'tcx> { pub fn check_decl_initializer(fcx: &FnCtxt, nid: ast::NodeId, init: &ast::Expr) - { +{ let local_ty = fcx.local_ty(init.span, nid); check_expr_coercable_to_type(fcx, init, local_ty) } From dbfa05411bad5d31cb594a02ddbf5333dcb0ad5a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jan 2015 07:23:21 -0500 Subject: [PATCH 19/29] Cleanup type-checking of constants, but do not try to fix #20489. --- src/librustc/middle/ty.rs | 4 ++++ src/librustc_typeck/check/_match.rs | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c720032bef264..0d853295502dc 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1779,6 +1779,10 @@ impl<'tcx> Generics<'tcx> { !self.regions.is_empty_in(space) } + pub fn is_empty(&self) -> bool { + self.types.is_empty() && self.regions.is_empty() + } + pub fn to_bounds(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>) -> GenericBounds<'tcx> { GenericBounds { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 7ff0e1758f526..49627120d2291 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -103,8 +103,18 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => { let const_did = tcx.def_map.borrow()[pat.id].clone().def_id(); let const_scheme = ty::lookup_item_type(tcx, const_did); - fcx.write_ty(pat.id, const_scheme.ty); - demand::suptype(fcx, pat.span, expected, const_scheme.ty); + assert!(const_scheme.generics.is_empty()); + let const_ty = pcx.fcx.instantiate_type_scheme(pat.span, + &Substs::empty(), + &const_scheme.ty); + fcx.write_ty(pat.id, const_ty); + + // FIXME(#20489) -- we should limit the types here to scalars or something! + + // As with PatLit, what we really want here is that there + // exist a LUB, but for the cases that can occur, subtype + // is good enough. + demand::suptype(fcx, pat.span, expected, const_ty); } ast::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map, pat) => { let typ = fcx.local_ty(pat.span, pat.id); From cc18053d9c070a65b6b5f686968ebd901c1d60c3 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Mon, 5 Jan 2015 03:19:34 +0200 Subject: [PATCH 20/29] bench: do not quit rt-messaging-ping-pong.rs early --- src/test/bench/rt-messaging-ping-pong.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/test/bench/rt-messaging-ping-pong.rs b/src/test/bench/rt-messaging-ping-pong.rs index adf773a2f252c..5ecc580de08d5 100644 --- a/src/test/bench/rt-messaging-ping-pong.rs +++ b/src/test/bench/rt-messaging-ping-pong.rs @@ -35,21 +35,24 @@ fn ping_pong_bench(n: uint, m: uint) { // Create a channel: B->A let (btx, brx) = channel(); - Thread::spawn(move|| { + let guard_a = Thread::spawn(move|| { let (tx, rx) = (atx, brx); for _ in range(0, n) { tx.send(()).unwrap(); rx.recv().unwrap(); } - }).detach(); + }); - Thread::spawn(move|| { + let guard_b = Thread::spawn(move|| { let (tx, rx) = (btx, arx); for _ in range(0, n) { rx.recv().unwrap(); tx.send(()).unwrap(); } - }).detach(); + }); + + guard_a.join().ok(); + guard_b.join().ok(); } for _ in range(0, m) { From fb1871dc1b5416392d777e21f8639c7e48a2839a Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Sun, 4 Jan 2015 02:35:14 -0800 Subject: [PATCH 21/29] Refactor struct parsing and add tests --- src/libsyntax/parse/parser.rs | 121 +++++++++++++++++---------- src/test/compile-fail/issue-17904.rs | 17 ++++ src/test/compile-fail/unsized.rs | 2 +- src/test/run-pass/issue-17904.rs | 4 - 4 files changed, 94 insertions(+), 50 deletions(-) create mode 100644 src/test/compile-fail/issue-17904.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 570ef67bbccfd..79e5fe7cc9a07 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4875,9 +4875,6 @@ impl<'a> Parser<'a> { self.span_err(ty.span, "`virtual` structs have been removed from the language"); } - let mut fields: Vec; - let is_tuple_like; - // There is a special case worth noting here, as reported in issue #17904. // If we are parsing a tuple struct it is the case that the where clause // should follow the field list. Like so: @@ -4892,68 +4889,102 @@ impl<'a> Parser<'a> { // Otherwise if we look ahead and see a paren we parse a tuple-style // struct. - // Will parse the where-clause if it precedes the brace. - self.parse_where_clause(&mut generics); + let (fields, ctor_id) = if self.token.is_keyword(keywords::Where) { + self.parse_where_clause(&mut generics); + if self.eat(&token::Semi) { + // If we see a: `struct Foo where T: Copy;` style decl. + (Vec::new(), Some(ast::DUMMY_NODE_ID)) + } else { + // If we see: `struct Foo where T: Copy { ... }` + (self.parse_record_struct_body(&class_name), None) + } + // No `where` so: `struct Foo;` + } else if self.eat(&token::Semi) { + (Vec::new(), Some(ast::DUMMY_NODE_ID)) + // Record-style struct definition + } else if self.token == token::OpenDelim(token::Brace) { + let fields = self.parse_record_struct_body(&class_name); + (fields, None) + // Tuple-style struct definition with optional where-clause. + } else { + let fields = self.parse_tuple_struct_body(&class_name, &mut generics); + (fields, Some(ast::DUMMY_NODE_ID)) + }; + (class_name, + ItemStruct(P(ast::StructDef { + fields: fields, + ctor_id: ctor_id, + }), generics), + None) + } + + pub fn parse_record_struct_body(&mut self, class_name: &ast::Ident) -> Vec { + let mut fields = Vec::new(); if self.eat(&token::OpenDelim(token::Brace)) { - // It's a record-like struct. - is_tuple_like = false; - fields = Vec::new(); while self.token != token::CloseDelim(token::Brace) { fields.push(self.parse_struct_decl_field(true)); } + if fields.len() == 0 { self.fatal(format!("unit-like struct definition should be \ - written as `struct {};`", - token::get_ident(class_name))[]); + written as `struct {};`", + token::get_ident(class_name.clone()))[]); } + self.bump(); - } else if self.check(&token::OpenDelim(token::Paren)) { - // It's a tuple-like struct. - is_tuple_like = true; - fields = self.parse_unspanned_seq( + } else { + let token_str = self.this_token_to_string(); + self.fatal(format!("expected `where`, or `{}` after struct \ + name, found `{}`", "{", + token_str)[]); + } + + fields + } + + pub fn parse_tuple_struct_body(&mut self, + class_name: &ast::Ident, + generics: &mut ast::Generics) + -> Vec { + // This is the case where we find `struct Foo(T) where T: Copy;` + if self.check(&token::OpenDelim(token::Paren)) { + let fields = self.parse_unspanned_seq( &token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), |p| { - let attrs = p.parse_outer_attributes(); - let lo = p.span.lo; - let struct_field_ = ast::StructField_ { - kind: UnnamedField(p.parse_visibility()), - id: ast::DUMMY_NODE_ID, - ty: p.parse_ty_sum(), - attrs: attrs, - }; - spanned(lo, p.span.hi, struct_field_) - }); + let attrs = p.parse_outer_attributes(); + let lo = p.span.lo; + let struct_field_ = ast::StructField_ { + kind: UnnamedField(p.parse_visibility()), + id: ast::DUMMY_NODE_ID, + ty: p.parse_ty_sum(), + attrs: attrs, + }; + spanned(lo, p.span.hi, struct_field_) + }); + if fields.len() == 0 { self.fatal(format!("unit-like struct definition should be \ - written as `struct {};`", - token::get_ident(class_name))[]); + written as `struct {};`", + token::get_ident(class_name.clone()))[]); } - self.parse_where_clause(&mut generics); + + self.parse_where_clause(generics); self.expect(&token::Semi); - } else if self.token.is_keyword(keywords::Where) || self.eat(&token::Semi) { - // We can find a where clause here. - self.parse_where_clause(&mut generics); - // It's a unit-like struct. - is_tuple_like = true; - fields = Vec::new(); + fields + // This is the case where we just see struct Foo where T: Copy; + } else if self.token.is_keyword(keywords::Where) { + self.parse_where_clause(generics); + self.expect(&token::Semi); + Vec::new() + // This case is where we see: `struct Foo;` } else { let token_str = self.this_token_to_string(); - self.fatal(format!("expected `{}`, `(`, or `;` after struct \ - name, found `{}`", "{", - token_str)[]) + self.fatal(format!("expected `where`, `{}`, `(`, or `;` after struct \ + name, found `{}`", "{", token_str)[]); } - - let _ = ast::DUMMY_NODE_ID; // FIXME: Workaround for crazy bug. - let new_id = ast::DUMMY_NODE_ID; - (class_name, - ItemStruct(P(ast::StructDef { - fields: fields, - ctor_id: if is_tuple_like { Some(new_id) } else { None }, - }), generics), - None) } /// Parse a structure field declaration diff --git a/src/test/compile-fail/issue-17904.rs b/src/test/compile-fail/issue-17904.rs new file mode 100644 index 0000000000000..0ef4c78cd38ad --- /dev/null +++ b/src/test/compile-fail/issue-17904.rs @@ -0,0 +1,17 @@ +// 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. + +struct Baz where U: Eq(U); // This is parsed as the new Fn* style parenthesis syntax. +struct Baz where U: Eq(U) -> R; // Notice this parses as well. +struct Baz(U) where U: Eq; // This rightfully signals no error as well. +struct Foo where T: Copy, (T); //^~ ERROR: unexpected token in `where` clause +struct Bar { x: T } where T: Copy //^~ ERROR: expected item, found `where` + +fn main() {} diff --git a/src/test/compile-fail/unsized.rs b/src/test/compile-fail/unsized.rs index 43db4dfd395b0..92dbea0424b6f 100644 --- a/src/test/compile-fail/unsized.rs +++ b/src/test/compile-fail/unsized.rs @@ -10,7 +10,7 @@ // Test syntax checks for `type` keyword. -struct S1 for type; //~ ERROR expected `{`, `(`, or `;` after struct name, found `for` +struct S1 for type; //~ ERROR expected `where`, `{`, `(`, or `;` after struct name, found `for` pub fn main() { } diff --git a/src/test/run-pass/issue-17904.rs b/src/test/run-pass/issue-17904.rs index c2976378ddad8..3ce347d67e3d9 100644 --- a/src/test/run-pass/issue-17904.rs +++ b/src/test/run-pass/issue-17904.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tests that type assignability is used to search for instances when -// making method calls, but only if there aren't any matches without -// it. - struct Foo where T: Copy; struct Bar(T) where T: Copy; struct Bleh(T, U) where T: Copy, U: Sized; From 540bec16deeb9846787da20c07d3c8618c2a8568 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 4 Jan 2015 21:39:02 -0500 Subject: [PATCH 22/29] sed -i -s 's/ for Sized?//g' **/*.rs --- src/libcollections/slice.rs | 4 ++-- src/libcollections/str.rs | 2 +- src/libcore/borrow.rs | 6 +++--- src/libcore/cmp.rs | 8 ++++---- src/libcore/fmt/mod.rs | 16 +++++++-------- src/libcore/hash/mod.rs | 2 +- src/libcore/kinds.rs | 8 ++++---- src/libcore/ops.rs | 20 +++++++++---------- src/libcore/raw.rs | 2 +- src/libcore/slice.rs | 8 ++++---- src/libcore/str/mod.rs | 4 ++-- src/librustc/middle/traits/util.rs | 2 +- src/librustc/util/ppaux.rs | 2 +- src/librustc_trans/trans/cabi_x86_64.rs | 2 +- src/librustc_trans/trans/llrepr.rs | 2 +- src/libserialize/base64.rs | 4 ++-- src/libserialize/hex.rs | 4 ++-- src/libserialize/json.rs | 2 +- src/libserialize/serialize.rs | 2 +- src/libstd/ascii.rs | 2 +- src/libstd/c_str.rs | 2 +- src/libstd/path/mod.rs | 2 +- src/libsyntax/ext/quote.rs | 4 ++-- src/libtest/stats.rs | 2 +- src/libunicode/u_str.rs | 2 +- src/test/auxiliary/lang-item-public.rs | 2 +- ...ed-types-ICE-when-projecting-out-of-err.rs | 2 +- .../dst-object-from-unsized-type.rs | 2 +- src/test/compile-fail/issue-18959.rs | 4 ++-- src/test/compile-fail/issue-19009.rs | 2 +- src/test/compile-fail/privacy4.rs | 2 +- src/test/compile-fail/required-lang-item.rs | 2 +- .../unboxed-closure-sugar-default.rs | 2 +- .../unboxed-closure-sugar-equiv.rs | 2 +- .../unboxed-closure-sugar-lifetime-elision.rs | 2 +- .../unboxed-closure-sugar-region.rs | 2 +- src/test/compile-fail/unsized3.rs | 2 +- src/test/compile-fail/unsized6.rs | 2 +- src/test/compile-fail/unsized7.rs | 2 +- .../associated-types-conditional-dispatch.rs | 2 +- ...sociated-types-normalize-in-bounds-ufcs.rs | 2 +- .../associated-types-normalize-in-bounds.rs | 2 +- 42 files changed, 75 insertions(+), 75 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 3602bfc10c307..a5e44dc1ddcff 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -120,7 +120,7 @@ pub use core::slice::{from_raw_buf, from_raw_mut_buf}; /// Allocating extension methods for slices. #[unstable = "needs associated types, may merge with other traits"] -pub trait SliceExt for Sized? { +pub trait SliceExt { type Item; /// Sorts the slice, in place, using `compare` to compare @@ -989,7 +989,7 @@ impl SliceExt for [T] { //////////////////////////////////////////////////////////////////////////////// #[unstable = "U should be an associated type"] /// An extension trait for concatenating slices -pub trait SliceConcatExt for Sized? { +pub trait SliceConcatExt { /// Flattens a slice of `T` into a single value `U`. #[stable] fn concat(&self) -> U; diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index ed6a957d2acfa..43004587bab3a 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -401,7 +401,7 @@ Section: Trait implementations */ /// Any string that can be represented as a slice. -pub trait StrExt for Sized?: ops::Slice { +pub trait StrExt: ops::Slice { /// Escapes each char in `s` with `char::escape_default`. #[unstable = "return type may change to be an iterator"] fn escape_default(&self) -> String { diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 7e4d73d598d8d..6695cae6a1cf6 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -53,13 +53,13 @@ use option::Option; use self::Cow::*; /// A trait for borrowing data. -pub trait BorrowFrom for Sized? { +pub trait BorrowFrom { /// Immutably borrow from an owned value. fn borrow_from(owned: &Owned) -> &Self; } /// A trait for mutably borrowing data. -pub trait BorrowFromMut for Sized? : BorrowFrom { +pub trait BorrowFromMut : BorrowFrom { /// Mutably borrow from an owned value. fn borrow_from_mut(owned: &mut Owned) -> &mut Self; } @@ -103,7 +103,7 @@ impl<'a, T, Sized? B> IntoCow<'a, T, B> for Cow<'a, T, B> where B: ToOwned { } /// A generalization of Clone to borrowed data. -pub trait ToOwned for Sized?: BorrowFrom { +pub trait ToOwned: BorrowFrom { /// Create owned data from borrowed data, usually by copying. fn to_owned(&self) -> Owned; } diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 13f9f5ccee916..c4ed0a75a4ec8 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -69,7 +69,7 @@ use option::Option::{self, Some, None}; /// only if `a != b`. #[lang="eq"] #[stable] -pub trait PartialEq for Sized? { +pub trait PartialEq { /// This method tests for `self` and `other` values to be equal, and is used by `==`. #[stable] fn eq(&self, other: &Rhs) -> bool; @@ -90,7 +90,7 @@ pub trait PartialEq for Sized? { /// - symmetric: `a == b` implies `b == a`; and /// - transitive: `a == b` and `b == c` implies `a == c`. #[stable] -pub trait Eq for Sized?: PartialEq { +pub trait Eq: PartialEq { // FIXME #13101: this method is used solely by #[deriving] to // assert that every component of a type implements #[deriving] // itself, the current deriving infrastructure means doing this @@ -164,7 +164,7 @@ impl Ordering { /// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for /// both `==` and `>`. #[stable] -pub trait Ord for Sized?: Eq + PartialOrd { +pub trait Ord: Eq + PartialOrd { /// This method returns an ordering between `self` and `other` values. /// /// By convention, `self.cmp(&other)` returns the ordering matching @@ -224,7 +224,7 @@ impl PartialOrd for Ordering { /// 5.11). #[lang="ord"] #[stable] -pub trait PartialOrd for Sized?: PartialEq { +pub trait PartialOrd: PartialEq { /// This method returns an ordering between `self` and `other` values /// if one exists. #[stable] diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index f49f87ff329f0..659af9938a16a 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -222,7 +222,7 @@ impl<'a> Show for Arguments<'a> { /// to this trait. There is not an explicit way of selecting this trait to be /// used for formatting, it is only if no other format is specified. #[unstable = "I/O and core have yet to be reconciled"] -pub trait Show for Sized? { +pub trait Show { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } @@ -230,49 +230,49 @@ pub trait Show for Sized? { /// Format trait for the `o` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait Octal for Sized? { +pub trait Octal { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `b` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait Binary for Sized? { +pub trait Binary { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `x` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait LowerHex for Sized? { +pub trait LowerHex { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `X` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait UpperHex for Sized? { +pub trait UpperHex { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `p` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait Pointer for Sized? { +pub trait Pointer { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `e` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait LowerExp for Sized? { +pub trait LowerExp { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `E` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait UpperExp for Sized? { +pub trait UpperExp { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index b0a5ec9fe12ed..d929e12a073c7 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -76,7 +76,7 @@ pub mod sip; /// A hashable type. The `S` type parameter is an abstract hash state that is /// used by the `Hash` to compute the hash. It defaults to /// `std::hash::sip::SipState`. -pub trait Hash for Sized? { +pub trait Hash { /// Computes the hash of a value. fn hash(&self, state: &mut S); } diff --git a/src/libcore/kinds.rs b/src/libcore/kinds.rs index e50aaef5f09f3..4769c783e5829 100644 --- a/src/libcore/kinds.rs +++ b/src/libcore/kinds.rs @@ -19,19 +19,19 @@ /// Types able to be transferred across task boundaries. #[lang="send"] -pub unsafe trait Send for Sized? : 'static { +pub unsafe trait Send : 'static { // empty. } /// Types with a constant size known at compile-time. #[lang="sized"] -pub trait Sized for Sized? { +pub trait Sized { // Empty. } /// Types that can be copied by simply copying bits (i.e. `memcpy`). #[lang="copy"] -pub trait Copy for Sized? { +pub trait Copy { // Empty. } @@ -81,7 +81,7 @@ pub trait Copy for Sized? { /// reference; not doing this is undefined behaviour (for example, /// `transmute`-ing from `&T` to `&mut T` is illegal). #[lang="sync"] -pub unsafe trait Sync for Sized? { +pub unsafe trait Sync { // Empty } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index c9b71092f9072..ef9f7f25c6a66 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -721,7 +721,7 @@ shr_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 } #[cfg(stage0)] #[allow(missing_docs)] #[lang="index"] -pub trait Index for Sized? { +pub trait Index { /// The method for the indexing (`Foo[Bar]`) operation fn index<'a>(&'a self, index: &Index) -> &'a Result; } @@ -757,7 +757,7 @@ pub trait Index for Sized? { /// ``` #[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot #[lang="index"] -pub trait Index for Sized? { +pub trait Index { type Sized? Output; /// The method for the indexing (`Foo[Bar]`) operation @@ -768,7 +768,7 @@ pub trait Index for Sized? { #[cfg(stage0)] #[allow(missing_docs)] #[lang="index_mut"] -pub trait IndexMut for Sized? { +pub trait IndexMut { /// The method for the indexing (`Foo[Bar]`) operation fn index_mut<'a>(&'a mut self, index: &Index) -> &'a mut Result; } @@ -804,7 +804,7 @@ pub trait IndexMut for Sized? { /// ``` #[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot #[lang="index_mut"] -pub trait IndexMut for Sized? { +pub trait IndexMut { type Sized? Output; /// The method for the indexing (`Foo[Bar]`) operation @@ -849,7 +849,7 @@ pub trait IndexMut for Sized? { /// } /// ``` #[lang="slice"] -pub trait Slice for Sized? { +pub trait Slice { /// The method for the slicing operation foo[] fn as_slice_<'a>(&'a self) -> &'a Result; /// The method for the slicing operation foo[from..] @@ -898,7 +898,7 @@ pub trait Slice for Sized? { /// } /// ``` #[lang="slice_mut"] -pub trait SliceMut for Sized? { +pub trait SliceMut { /// The method for the slicing operation foo[] fn as_mut_slice_<'a>(&'a mut self) -> &'a mut Result; /// The method for the slicing operation foo[from..] @@ -1025,7 +1025,7 @@ pub struct RangeTo { /// } /// ``` #[lang="deref"] -pub trait Deref for Sized? { +pub trait Deref { type Sized? Target; /// The method called to dereference a value @@ -1082,7 +1082,7 @@ impl<'a, Sized? T> Deref for &'a mut T { /// } /// ``` #[lang="deref_mut"] -pub trait DerefMut for Sized? : Deref { +pub trait DerefMut : Deref { /// The method called to mutably dereference a value fn deref_mut<'a>(&'a mut self) -> &'a mut ::Target; } @@ -1093,14 +1093,14 @@ impl<'a, Sized? T> DerefMut for &'a mut T { /// A version of the call operator that takes an immutable receiver. #[lang="fn"] -pub trait Fn for Sized? { +pub trait Fn { /// This is called when the call operator is used. extern "rust-call" fn call(&self, args: Args) -> Result; } /// A version of the call operator that takes a mutable receiver. #[lang="fn_mut"] -pub trait FnMut for Sized? { +pub trait FnMut { /// This is called when the call operator is used. extern "rust-call" fn call_mut(&mut self, args: Args) -> Result; } diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index 3bef1d1536377..0e91d6123f5cc 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -52,7 +52,7 @@ pub struct TraitObject { /// This trait is meant to map equivalences between raw structs and their /// corresponding rust values. -pub trait Repr for Sized? { +pub trait Repr { /// This function "unwraps" a rust value (without consuming it) into its raw /// struct representation. This can be used to read/write different values /// for the struct. This is a safe method because by default it does not diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index f17a775cf4240..9aa3f76b525e7 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -64,7 +64,7 @@ use raw::Slice as RawSlice; /// Extension methods for slices. #[allow(missing_docs)] // docs in libcollections -pub trait SliceExt for Sized? { +pub trait SliceExt { type Item; fn slice<'a>(&'a self, start: uint, end: uint) -> &'a [Self::Item]; @@ -636,7 +636,7 @@ impl ops::SliceMut for [T] { /// Data that is viewable as a slice. #[experimental = "will be replaced by slice syntax"] -pub trait AsSlice for Sized? { +pub trait AsSlice { /// Work with `self` as a slice. fn as_slice<'a>(&'a self) -> &'a [T]; } @@ -1377,7 +1377,7 @@ pub mod bytes { use slice::SliceExt; /// A trait for operations on mutable `[u8]`s. - pub trait MutableByteVector for Sized? { + pub trait MutableByteVector { /// Sets all bytes of the receiver to the given value. fn set_memory(&mut self, value: u8); } @@ -1461,7 +1461,7 @@ impl PartialOrd for [T] { /// Extension methods for slices containing integers. #[experimental] -pub trait IntSliceExt for Sized? { +pub trait IntSliceExt { /// Converts the slice to an immutable slice of unsigned integers with the same width. fn as_unsigned<'a>(&'a self) -> &'a [U]; /// Converts the slice to an immutable slice of signed integers with the same width. diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index d069744f8da54..ccbc444963c9d 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1130,7 +1130,7 @@ pub mod traits { #[unstable = "Instead of taking this bound generically, this trait will be \ replaced with one of slicing syntax, deref coercions, or \ a more generic conversion trait"] -pub trait Str for Sized? { +pub trait Str { /// Work with `self` as a slice. fn as_slice<'a>(&'a self) -> &'a str; } @@ -1171,7 +1171,7 @@ delegate_iter!{pattern forward &'a str in RSplitN<'a, P>} /// Methods for string slices #[allow(missing_docs)] -pub trait StrExt for Sized? { +pub trait StrExt { // NB there are no docs here are they're all located on the StrExt trait in // libcollections, not here. diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index ab8888f9a33eb..8152f7e284fe4 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -93,7 +93,7 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { // seen. This is necessary to prevent infinite // recursion in some cases. One common case is when // people define `trait Sized { }` rather than `trait - // Sized for Sized? { }`. + // Sized { }`. predicates.retain(|r| self.visited.insert(r.clone())); self.stack.push(StackEntry { position: 0, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 9639af5ca1cd5..0c7c9513719ac 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -38,7 +38,7 @@ use syntax::{ast, ast_util}; use syntax::owned_slice::OwnedSlice; /// Produces a string suitable for debugging output. -pub trait Repr<'tcx> for Sized? { +pub trait Repr<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String; } diff --git a/src/librustc_trans/trans/cabi_x86_64.rs b/src/librustc_trans/trans/cabi_x86_64.rs index f59d152fa473c..9ec0c822bf5fe 100644 --- a/src/librustc_trans/trans/cabi_x86_64.rs +++ b/src/librustc_trans/trans/cabi_x86_64.rs @@ -63,7 +63,7 @@ impl RegClass { } } -trait ClassList for Sized? { +trait ClassList { fn is_pass_byval(&self) -> bool; fn is_ret_bysret(&self) -> bool; } diff --git a/src/librustc_trans/trans/llrepr.rs b/src/librustc_trans/trans/llrepr.rs index dcf3a53215788..de0f714276d0d 100644 --- a/src/librustc_trans/trans/llrepr.rs +++ b/src/librustc_trans/trans/llrepr.rs @@ -12,7 +12,7 @@ use trans::context::CrateContext; use trans::type_::Type; use llvm::ValueRef; -pub trait LlvmRepr for Sized? { +pub trait LlvmRepr { fn llrepr(&self, ccx: &CrateContext) -> String; } diff --git a/src/libserialize/base64.rs b/src/libserialize/base64.rs index 44bf5f8977870..11a49cd712f25 100644 --- a/src/libserialize/base64.rs +++ b/src/libserialize/base64.rs @@ -70,7 +70,7 @@ static URLSAFE_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 0123456789-_"; /// A trait for converting a value to base64 encoding. -pub trait ToBase64 for Sized? { +pub trait ToBase64 { /// Converts the value of `self` to a base64 value following the specified /// format configuration, returning the owned string. fn to_base64(&self, config: Config) -> String; @@ -170,7 +170,7 @@ impl ToBase64 for [u8] { } /// A trait for converting from base64 encoded values. -pub trait FromBase64 for Sized? { +pub trait FromBase64 { /// Converts the value of `self`, interpreted as base64 encoded data, into /// an owned vector of bytes, returning the vector. fn from_base64(&self) -> Result, FromBase64Error>; diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index c915ddaaa9c04..542d0678526b9 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -18,7 +18,7 @@ use std::fmt; use std::error; /// A trait for converting a value to hexadecimal encoding -pub trait ToHex for Sized? { +pub trait ToHex { /// Converts the value of `self` to a hex value, returning the owned /// string. fn to_hex(&self) -> String; @@ -54,7 +54,7 @@ impl ToHex for [u8] { } /// A trait for converting hexadecimal encoded values -pub trait FromHex for Sized? { +pub trait FromHex { /// Converts the value of `self`, interpreted as hexadecimal encoded data, /// into an owned vector of bytes, returning the vector. fn from_hex(&self) -> Result, FromHexError>; diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index e31d8157332c9..e868e1c269dbe 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2319,7 +2319,7 @@ impl ::Decoder for Decoder { } /// A trait for converting values to JSON -pub trait ToJson for Sized? { +pub trait ToJson { /// Converts the value of `self` to an instance of JSON fn to_json(&self) -> Json; } diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 558f9e603e159..ec195861310b5 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -172,7 +172,7 @@ pub trait Decoder { fn error(&mut self, err: &str) -> E; } -pub trait Encodable, E> for Sized? { +pub trait Encodable, E> { fn encode(&self, s: &mut S) -> Result<(), E>; } diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index bcd87f6786d35..c0b9bbbbc297d 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -38,7 +38,7 @@ pub trait OwnedAsciiExt { /// 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? { +pub trait AsciiExt { /// Check if within the ASCII range. fn is_ascii(&self) -> bool; diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index 9c96a9cac7831..a7f0bc3532fbe 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -295,7 +295,7 @@ impl fmt::Show for CString { } /// A generic trait for converting a value to a CString. -pub trait ToCStr for Sized? { +pub trait ToCStr { /// Copy the receiver into a CString. /// /// # Panics diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index bf9ffbffe7d50..ac281439ce545 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -786,7 +786,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe { } /// A trait that represents something bytes-like (e.g. a &[u8] or a &str) -pub trait BytesContainer for Sized? { +pub trait BytesContainer { /// 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 diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index e46bd7ac4bc73..f1b52fa33c386 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -85,14 +85,14 @@ pub mod rt { */ // FIXME: Move this trait to pprust and get rid of *_to_str? - pub trait ToSource for Sized? { + pub trait ToSource { // Takes a thing and generates a string containing rust code for it. fn to_source(&self) -> String; } // FIXME (Issue #16472): This should go away after ToToken impls // are revised to go directly to token-trees. - trait ToSourceWithHygiene for Sized? : ToSource { + trait ToSourceWithHygiene : ToSource { // Takes a thing and generates a string containing rust code // for it, encoding Idents as special byte sequences to // maintain hygiene across serialization and deserialization. diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 35af0e763d7dd..6139559335121 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -39,7 +39,7 @@ fn local_sort(v: &mut [T]) { } /// Trait that provides simple descriptive statistics on a univariate set of numeric samples. -pub trait Stats for Sized? { +pub trait Stats { /// Sum of the samples. /// diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index 1b0c4171134ed..90ab3dc37e96b 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -37,7 +37,7 @@ pub struct Words<'a> { /// Methods for Unicode string slices #[allow(missing_docs)] // docs in libcollections -pub trait UnicodeStr for Sized? { +pub trait UnicodeStr { fn graphemes<'a>(&'a self, is_extended: bool) -> Graphemes<'a>; fn grapheme_indices<'a>(&'a self, is_extended: bool) -> GraphemeIndices<'a>; fn words<'a>(&'a self) -> Words<'a>; diff --git a/src/test/auxiliary/lang-item-public.rs b/src/test/auxiliary/lang-item-public.rs index e6bae4628874c..e99a8f0b87737 100644 --- a/src/test/auxiliary/lang-item-public.rs +++ b/src/test/auxiliary/lang-item-public.rs @@ -12,7 +12,7 @@ #![feature(lang_items)] #[lang="sized"] -pub trait Sized for Sized? {} +pub trait Sized {} #[lang="panic"] fn panic(_: &(&'static str, &'static str, uint)) -> ! { loop {} } diff --git a/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs index 5743216b6ca69..6265392663dec 100644 --- a/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs +++ b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs @@ -16,7 +16,7 @@ #![no_std] #[lang="sized"] -pub trait Sized for Sized? { +pub trait Sized { // Empty. } diff --git a/src/test/compile-fail/dst-object-from-unsized-type.rs b/src/test/compile-fail/dst-object-from-unsized-type.rs index 99c63c3c6e95e..4e5a6be1bc7c6 100644 --- a/src/test/compile-fail/dst-object-from-unsized-type.rs +++ b/src/test/compile-fail/dst-object-from-unsized-type.rs @@ -10,7 +10,7 @@ // Test that we cannot create objects from unsized types. -trait Foo for Sized? {} +trait Foo {} impl Foo for str {} fn test1(t: &T) { diff --git a/src/test/compile-fail/issue-18959.rs b/src/test/compile-fail/issue-18959.rs index 1a792eb6e76ae..7aba1bc8e65c7 100644 --- a/src/test/compile-fail/issue-18959.rs +++ b/src/test/compile-fail/issue-18959.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub trait Foo for Sized? { fn foo(&self, ext_thing: &T); } -pub trait Bar for Sized?: Foo { } +pub trait Foo { fn foo(&self, ext_thing: &T); } +pub trait Bar: Foo { } impl Bar for T { } pub struct Thing; diff --git a/src/test/compile-fail/issue-19009.rs b/src/test/compile-fail/issue-19009.rs index aa7c4c3060bdb..3c1853b9990a7 100644 --- a/src/test/compile-fail/issue-19009.rs +++ b/src/test/compile-fail/issue-19009.rs @@ -11,7 +11,7 @@ #![feature(lang_items)] #![no_std] #![crate_type="rlib"] -#[lang="sized"] pub trait Sized for Sized? {} +#[lang="sized"] pub trait Sized {} fn ice(f: for <'s> || :'s //~ ERROR use of undeclared lifetime name `'s` diff --git a/src/test/compile-fail/privacy4.rs b/src/test/compile-fail/privacy4.rs index 70e7e2df98a69..3d8b3eda044d4 100644 --- a/src/test/compile-fail/privacy4.rs +++ b/src/test/compile-fail/privacy4.rs @@ -11,7 +11,7 @@ #![feature(globs, lang_items)] #![no_std] // makes debugging this test *a lot* easier (during resolve) -#[lang = "sized"] pub trait Sized for Sized? {} +#[lang = "sized"] pub trait Sized {} #[lang="copy"] pub trait Copy {} // Test to make sure that private items imported through globs remain private diff --git a/src/test/compile-fail/required-lang-item.rs b/src/test/compile-fail/required-lang-item.rs index dd11ec645b42e..ae561878e9ba0 100644 --- a/src/test/compile-fail/required-lang-item.rs +++ b/src/test/compile-fail/required-lang-item.rs @@ -11,7 +11,7 @@ #![feature(lang_items)] #![no_std] -#[lang="sized"] pub trait Sized for Sized? {} +#[lang="sized"] pub trait Sized {} // error-pattern:requires `start` lang_item diff --git a/src/test/compile-fail/unboxed-closure-sugar-default.rs b/src/test/compile-fail/unboxed-closure-sugar-default.rs index 06a934063927a..75f2a1744db15 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-default.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-default.rs @@ -18,7 +18,7 @@ trait Foo { fn dummy(&self, t: T, u: U, v: V); } -trait Eq for Sized? { } +trait Eq { } impl Eq for X { } fn eq() where A : Eq { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-equiv.rs b/src/test/compile-fail/unboxed-closure-sugar-equiv.rs index 16d6b217872ae..2b2327277a2d1 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-equiv.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-equiv.rs @@ -20,7 +20,7 @@ trait Foo { fn dummy(&self, t: T, u: U); } -trait Eq for Sized? { } +trait Eq { } impl Eq for X { } fn eq>() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs b/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs index e08d84944c02a..9ec6428de27a0 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs @@ -20,7 +20,7 @@ trait Foo { fn dummy(&self, t: T, u: U); } -trait Eq for Sized? { } +trait Eq { } impl Eq for X { } fn eq>() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-region.rs b/src/test/compile-fail/unboxed-closure-sugar-region.rs index a938f126c1607..a2225b0615b01 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-region.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-region.rs @@ -21,7 +21,7 @@ trait Foo<'a,T,U> { fn dummy(&'a self) -> &'a (T,U); } -trait Eq for Sized? { } +trait Eq { } impl Eq for X { } fn eq>() { } diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index 0a75240f2d89d..76a6f01b18322 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -20,7 +20,7 @@ fn f2(x: &X) { } // Bounded. -trait T for Sized? {} +trait T {} fn f3(x: &X) { f4::(x); //~^ ERROR the trait `core::kinds::Sized` is not implemented diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index 0efd178f75b8c..4fcf7707f07fe 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -11,7 +11,7 @@ // Test `Sized?` local variables. -trait T for Sized? {} +trait T {} fn f1(x: &X) { let _: X; // <-- this is OK, no bindings created, no initializer. diff --git a/src/test/compile-fail/unsized7.rs b/src/test/compile-fail/unsized7.rs index c0e6ae1db92c4..e919f04971319 100644 --- a/src/test/compile-fail/unsized7.rs +++ b/src/test/compile-fail/unsized7.rs @@ -10,7 +10,7 @@ // Test sized-ness checking in substitution in impls. -trait T for Sized? {} +trait T {} // I would like these to fail eventually. // impl - bounded diff --git a/src/test/run-pass/associated-types-conditional-dispatch.rs b/src/test/run-pass/associated-types-conditional-dispatch.rs index 3b53203d218e0..213775d86f40d 100644 --- a/src/test/run-pass/associated-types-conditional-dispatch.rs +++ b/src/test/run-pass/associated-types-conditional-dispatch.rs @@ -18,7 +18,7 @@ use std::ops::Deref; -pub trait MyEq for Sized? { +pub trait MyEq { fn eq(&self, u: &U) -> bool; } diff --git a/src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs b/src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs index 0fd477204215e..8f1523e736dc5 100644 --- a/src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs +++ b/src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs @@ -16,7 +16,7 @@ struct Splits<'a, T, P>; struct SplitsN; -trait SliceExt2 for Sized? { +trait SliceExt2 { type Item; fn split2<'a, P>(&'a self, pred: P) -> Splits<'a, Self::Item, P> diff --git a/src/test/run-pass/associated-types-normalize-in-bounds.rs b/src/test/run-pass/associated-types-normalize-in-bounds.rs index f09c27029d7fa..f00c822bee0a5 100644 --- a/src/test/run-pass/associated-types-normalize-in-bounds.rs +++ b/src/test/run-pass/associated-types-normalize-in-bounds.rs @@ -16,7 +16,7 @@ struct Splits<'a, T, P>; struct SplitsN; -trait SliceExt2 for Sized? { +trait SliceExt2 { type Item; fn split2<'a, P>(&'a self, pred: P) -> Splits<'a, Self::Item, P> From 0995c607e1d26f04c3709867f4f8a06e06df9627 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 4 Jan 2015 21:47:03 -0500 Subject: [PATCH 23/29] remove unused `Sized` imports --- src/libcollections/str.rs | 1 - src/libcore/raw.rs | 1 - src/libcore/slice.rs | 1 - src/libstd/ascii.rs | 1 - 4 files changed, 4 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 43004587bab3a..bae376c63fc98 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -59,7 +59,6 @@ use core::char::Char; use core::clone::Clone; use core::iter::AdditiveIterator; use core::iter::{range, Iterator, IteratorExt}; -use core::kinds::Sized; use core::ops; use core::option::Option::{self, Some, None}; use core::slice::AsSlice; diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index 0e91d6123f5cc..5ef6f6b2623aa 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -20,7 +20,6 @@ use kinds::Copy; use mem; -use kinds::Sized; /// The representation of a Rust slice #[repr(C)] diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 9aa3f76b525e7..1fde906062ec4 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1372,7 +1372,6 @@ pub unsafe fn from_raw_mut_buf<'a, T>(p: &'a *mut T, len: uint) -> &'a mut [T] { /// Operations on `[u8]`. #[experimental = "needs review"] pub mod bytes { - use kinds::Sized; use ptr; use slice::SliceExt; diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index c0b9bbbbc297d..abd4c7faa5bda 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -14,7 +14,6 @@ #![unstable = "unsure about placement and naming"] -use core::kinds::Sized; use iter::IteratorExt; use ops::FnMut; use slice::SliceExt; From 04b006acbc75a0a5ac54ae871ea0a13dc56111fb Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 4 Jan 2015 21:48:57 -0500 Subject: [PATCH 24/29] undo one `for Sized?` removal that was in a comment --- src/librustc/middle/traits/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 8152f7e284fe4..ab8888f9a33eb 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -93,7 +93,7 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { // seen. This is necessary to prevent infinite // recursion in some cases. One common case is when // people define `trait Sized { }` rather than `trait - // Sized { }`. + // Sized for Sized? { }`. predicates.retain(|r| self.visited.insert(r.clone())); self.stack.push(StackEntry { position: 0, From 8abcbf9b71b87651213eb6d4b13923c648a6e577 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 4 Jan 2015 23:20:17 -0500 Subject: [PATCH 25/29] update comment to reflect new `Sized` semantics --- src/librustc/middle/traits/util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index ab8888f9a33eb..229d34fe4237c 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -92,8 +92,8 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { // Only keep those bounds that we haven't already // seen. This is necessary to prevent infinite // recursion in some cases. One common case is when - // people define `trait Sized { }` rather than `trait - // Sized for Sized? { }`. + // people define `trait Sized: Sized { }` rather than `trait + // Sized { }`. predicates.retain(|r| self.visited.insert(r.clone())); self.stack.push(StackEntry { position: 0, From bf6c007760169e9c382d3700fd1cdd20037e4343 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Fri, 5 Dec 2014 15:56:25 -0800 Subject: [PATCH 26/29] Change `&` pat to only work with &T, and `&mut` with &mut T. This implements RFC 179 by making the pattern `&` require matching against a variable of type `&T`, and introducing the pattern `&mut ` which only works with variables of type `&mut T`. The pattern `&mut x` currently parses as `&(mut x)` i.e. a pattern match through a `&T` or a `&mut T` that binds the variable `x` to have type `T` and to be mutable. This should be rewritten as follows, for example, for &mut x in slice.iter() { becomes for &x in slice.iter() { let mut x = x; Due to this, this is a [breaking-change] Closes #20496. --- src/doc/reference.md | 5 ++-- src/libcore/str/mod.rs | 2 +- src/librustc/middle/cfg/construct.rs | 2 +- src/librustc/middle/check_match.rs | 6 ++--- src/librustc/middle/mem_categorization.rs | 6 +++-- src/librustc_trans/trans/_match.rs | 4 +-- src/librustc_trans/trans/debuginfo.rs | 2 +- src/librustc_typeck/check/_match.rs | 10 ++++--- src/librustdoc/clean/mod.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/ext/deriving/generic/mod.rs | 2 +- src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/parser.rs | 9 +++++-- src/libsyntax/print/pprust.rs | 5 +++- src/libsyntax/visit.rs | 2 +- src/libtest/stats.rs | 3 ++- .../mut-pattern-internal-mutability.rs | 24 +++++++++++++++++ .../compile-fail/mut-pattern-mismatched.rs | 26 +++++++++++++++++++ 19 files changed, 91 insertions(+), 25 deletions(-) create mode 100644 src/test/compile-fail/mut-pattern-internal-mutability.rs create mode 100644 src/test/compile-fail/mut-pattern-mismatched.rs diff --git a/src/doc/reference.md b/src/doc/reference.md index d793028526052..0d3f9430bd677 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3484,8 +3484,9 @@ fn main() { ``` -Patterns can also dereference pointers by using the `&`, `box` symbols, -as appropriate. For example, these two matches on `x: &int` are equivalent: +Patterns can also dereference pointers by using the `&`, `&mut` and `box` +symbols, as appropriate. For example, these two matches on `x: &int` are +equivalent: ``` # let x = &3i; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index d069744f8da54..b497e9733bc9e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -230,7 +230,7 @@ impl CharEq for F where F: FnMut(char) -> bool { impl<'a> CharEq for &'a [char] { #[inline] fn matches(&mut self, c: char) -> bool { - self.iter().any(|&mut m| m.matches(c)) + self.iter().any(|&m| { let mut m = m; m.matches(c) }) } #[inline] diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index de81f307c4d7c..3c672d0fdb6fa 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -119,7 +119,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } ast::PatBox(ref subpat) | - ast::PatRegion(ref subpat) | + ast::PatRegion(ref subpat, _) | ast::PatIdent(_, _, Some(ref subpat)) => { let subpat_exit = self.pat(&**subpat, pred); self.add_node(pat.id, &[subpat_exit]) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 2d9284846acf3..f2b9ecb5ec432 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -473,7 +473,7 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, } } - ty::ty_rptr(_, ty::mt { ty, .. }) => { + ty::ty_rptr(_, ty::mt { ty, mutbl }) => { match ty.sty { ty::ty_vec(_, Some(n)) => match ctor { &Single => { @@ -493,7 +493,7 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, _ => { assert_eq!(pats_len, 1); - ast::PatRegion(pats.nth(0).unwrap()) + ast::PatRegion(pats.nth(0).unwrap(), mutbl) } } } @@ -860,7 +860,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], ast::PatTup(ref args) => Some(args.iter().map(|p| &**p).collect()), - ast::PatBox(ref inner) | ast::PatRegion(ref inner) => + ast::PatBox(ref inner) | ast::PatRegion(ref inner, _) => Some(vec![&**inner]), ast::PatLit(ref expr) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 31c3ca4199feb..f600086fc5e62 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1262,8 +1262,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } } - ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => { - // @p1, ~p1, ref p1 + ast::PatBox(ref subpat) | ast::PatRegion(ref subpat, _) => { + // box p1, &p1, &mut p1. we can ignore the mutability of + // PatRegion since that information is already contained + // in the type. let subcmt = try!(self.cat_deref(pat, cmt, 0, false)); try!(self.cat_pattern_(subcmt, &**subpat, op)); } diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 50cbe664b9079..fed0931cab71d 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -683,7 +683,7 @@ fn any_uniq_pat(m: &[Match], col: uint) -> bool { } fn any_region_pat(m: &[Match], col: uint) -> bool { - any_pat!(m, col, ast::PatRegion(_)) + any_pat!(m, col, ast::PatRegion(..)) } fn any_irrefutable_adt_pat(tcx: &ty::ctxt, m: &[Match], col: uint) -> bool { @@ -1725,7 +1725,7 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llbox = Load(bcx, val); bcx = bind_irrefutable_pat(bcx, &**inner, llbox, cleanup_scope); } - ast::PatRegion(ref inner) => { + ast::PatRegion(ref inner, _) => { let loaded_val = Load(bcx, val); bcx = bind_irrefutable_pat(bcx, &**inner, loaded_val, cleanup_scope); } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 916fcbfe13ef7..0789be956429c 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -3472,7 +3472,7 @@ fn create_scope_map(cx: &CrateContext, } } - ast::PatBox(ref sub_pat) | ast::PatRegion(ref sub_pat) => { + ast::PatBox(ref sub_pat) | ast::PatRegion(ref sub_pat, _) => { scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); walk_pattern(cx, &**sub_pat, scope_stack, scope_map); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index d8b410abf8449..1efff9d41f1ba 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -146,12 +146,16 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, check_pat(pcx, &**inner, tcx.types.err); } } - ast::PatRegion(ref inner) => { + ast::PatRegion(ref inner, mutbl) => { let inner_ty = fcx.infcx().next_ty_var(); - let mutbl = + // SNAP c894171 remove this `if`-`else` entirely after next snapshot + let mutbl = if mutbl == ast::MutImmutable { ty::deref(fcx.infcx().shallow_resolve(expected), true) - .map_or(ast::MutImmutable, |mt| mt.mutbl); + .map_or(ast::MutImmutable, |mt| mt.mutbl) + } else { + mutbl + }; let mt = ty::mt { ty: inner_ty, mutbl: mutbl }; let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f4d0bb79d88d6..6a4337a664b78 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2235,7 +2235,7 @@ fn name_from_pat(p: &ast::Pat) -> String { PatTup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p)) .collect::>().connect(", ")), PatBox(ref p) => name_from_pat(&**p), - PatRegion(ref p) => name_from_pat(&**p), + PatRegion(ref p, _) => name_from_pat(&**p), PatLit(..) => { warn!("tried to get argument name from PatLit, \ which is silly in function arguments"); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a33ee44be8968..d61b7a17a930d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -556,7 +556,7 @@ pub enum Pat_ { PatStruct(Path, Vec>, bool), PatTup(Vec>), PatBox(P), - PatRegion(P), // reference pattern + PatRegion(P, Mutability), // reference pattern PatLit(P), PatRange(P, P), /// [a, b, ..i, y, z] is represented as: diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 4026da6cf8e47..5e03afec16cf8 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -633,7 +633,7 @@ pub fn walk_pat(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool { PatEnum(_, Some(ref s)) | PatTup(ref s) => { s.iter().all(|p| walk_pat_(&**p, it)) } - PatBox(ref s) | PatRegion(ref s) => { + PatBox(ref s) | PatRegion(ref s, _) => { walk_pat_(&**s, it) } PatVec(ref before, ref slice, ref after) => { diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 8863de8757bf7..d522c346fa0ee 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -940,7 +940,7 @@ impl<'a> MethodDef<'a> { &**variant, self_arg_name, ast::MutImmutable); - (cx.pat(sp, ast::PatRegion(p)), idents) + (cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents) }; // A single arm has form (&VariantK, &VariantK, ...) => BodyK diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 3d3068f6868c6..03a4f9046b549 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1267,7 +1267,7 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { } PatTup(elts) => PatTup(elts.move_map(|x| folder.fold_pat(x))), PatBox(inner) => PatBox(folder.fold_pat(inner)), - PatRegion(inner) => PatRegion(folder.fold_pat(inner)), + PatRegion(inner, mutbl) => PatRegion(folder.fold_pat(inner), mutbl), PatRange(e1, e2) => { PatRange(folder.fold_expr(e1), folder.fold_expr(e2)) }, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 37ac86a33242e..d9183ef0c49f5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3357,11 +3357,16 @@ impl<'a> Parser<'a> { }) } token::BinOp(token::And) | token::AndAnd => { - // parse &pat + // parse &pat and &mut pat let lo = self.span.lo; self.expect_and(); + let mutability = if self.eat_keyword(keywords::Mut) { + ast::MutMutable + } else { + ast::MutImmutable + }; let sub = self.parse_pat(); - pat = PatRegion(sub); + pat = PatRegion(sub, mutability); hi = self.last_span.hi; return P(ast::Pat { id: ast::DUMMY_NODE_ID, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 9702c79719c64..9b2ee9de3584e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2092,8 +2092,11 @@ impl<'a> State<'a> { try!(word(&mut self.s, "box ")); try!(self.print_pat(&**inner)); } - ast::PatRegion(ref inner) => { + ast::PatRegion(ref inner, mutbl) => { try!(word(&mut self.s, "&")); + if mutbl == ast::MutMutable { + try!(word(&mut self.s, "mut ")); + } try!(self.print_pat(&**inner)); } ast::PatLit(ref e) => try!(self.print_expr(&**e)), diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ec6b2cfa5c396..99701ec971003 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -519,7 +519,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { } } PatBox(ref subpattern) | - PatRegion(ref subpattern) => { + PatRegion(ref subpattern, _) => { visitor.visit_pat(&**subpattern) } PatIdent(_, ref pth1, ref optional_subpattern) => { diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 35af0e763d7dd..c42cf4d055166 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -169,7 +169,8 @@ impl Stats for [T] { fn sum(&self) -> T { let mut partials = vec![]; - for &mut x in self.iter() { + for &x in self.iter() { + let mut x = x; let mut j = 0; // This inner loop applies `hi`/`lo` summation to each // partial so that the list of partial sums remains exact. diff --git a/src/test/compile-fail/mut-pattern-internal-mutability.rs b/src/test/compile-fail/mut-pattern-internal-mutability.rs new file mode 100644 index 0000000000000..05c6c4a96557c --- /dev/null +++ b/src/test/compile-fail/mut-pattern-internal-mutability.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +fn main() { + let foo = &mut 1i; + + let &mut x = foo; + x += 1; //~ ERROR re-assignment of immutable variable + + // explicitly mut-ify internals + let &mut mut x = foo; + x += 1; + + // check borrowing is detected successfully + let &mut ref x = foo; + *foo += 1; //~ ERROR cannot assign to `*foo` because it is borrowed +} diff --git a/src/test/compile-fail/mut-pattern-mismatched.rs b/src/test/compile-fail/mut-pattern-mismatched.rs new file mode 100644 index 0000000000000..74e6141a2b3ff --- /dev/null +++ b/src/test/compile-fail/mut-pattern-mismatched.rs @@ -0,0 +1,26 @@ +// 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. + +fn main() { + let foo = &mut 1i; + + // (separate lines to ensure the spans are accurate) + + // SNAP c894171 uncomment this after the next snapshot + // NOTE(stage0) just in case tidy doesn't check SNAP's in tests + // let &_ // ~ ERROR expected `&mut int`, found `&_` + // = foo; + let &mut _ = foo; + + let bar = &1i; + let &_ = bar; + let &mut _ //~ ERROR expected `&int`, found `&mut _` + = bar; +} From 5deef524df835ca5819cdb22626718b1a5b810ba Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 25 Nov 2014 13:28:35 -0800 Subject: [PATCH 27/29] std: Redesign c_str and c_vec This commit is an implementation of [RFC 494][rfc] which removes the entire `std::c_vec` module and redesigns the `std::c_str` module as `std::ffi`. [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0494-c_str-and-c_vec-stability.md The interface of the new `CString` is outlined in the linked RFC, the primary changes being: * The `ToCStr` trait is gone, meaning the `with_c_str` and `to_c_str` methods are now gone. These two methods are replaced with a `CString::from_slice` method. * The `CString` type is now just a wrapper around `Vec` with a static guarantee that there is a trailing nul byte with no internal nul bytes. This means that `CString` now implements `Deref`, which is where it gains most of its methods from. A few helper methods are added to acquire a slice of `u8` instead of `c_char`, as well as including a slice with the trailing nul byte if necessary. * All usage of non-owned `CString` values is now done via two functions inside of `std::ffi`, called `c_str_to_bytes` and `c_str_to_bytes_with_nul`. These functions are now the one method used to convert a `*const c_char` to a Rust slice of `u8`. Many more details, including newly deprecated methods, can be found linked in the RFC. This is a: [breaking-change] Closes #20444 --- src/doc/guide-ffi.md | 50 +- src/libcollections/string.rs | 24 - src/libcore/str/mod.rs | 2 +- src/libflate/lib.rs | 43 +- src/librustc/metadata/cstore.rs | 4 +- src/librustc/metadata/loader.rs | 12 +- src/librustc_llvm/archive_ro.rs | 13 +- src/librustc_llvm/lib.rs | 7 +- src/librustc_trans/back/lto.rs | 13 +- src/librustc_trans/back/write.rs | 112 ++- src/librustc_trans/trans/asm.rs | 19 +- src/librustc_trans/trans/base.rs | 89 +- src/librustc_trans/trans/builder.rs | 26 +- src/librustc_trans/trans/common.rs | 31 +- src/librustc_trans/trans/consts.rs | 6 +- src/librustc_trans/trans/context.rs | 27 +- src/librustc_trans/trans/debuginfo.rs | 526 ++++++------ src/librustc_trans/trans/foreign.rs | 28 +- src/librustc_trans/trans/glue.rs | 12 +- src/librustc_trans/trans/meth.rs | 8 +- src/librustc_trans/trans/type_.rs | 5 +- src/librustdoc/flock.rs | 10 +- src/librustdoc/html/markdown.rs | 16 +- src/libstd/c_str.rs | 857 ------------------- src/libstd/c_vec.rs | 232 ----- src/libstd/dynamic_lib.rs | 42 +- src/libstd/ffi/c_str.rs | 218 +++++ src/libstd/ffi/mod.rs | 20 + src/libstd/io/net/pipe.rs | 21 +- src/libstd/io/process.rs | 70 +- src/libstd/lib.rs | 6 +- src/libstd/os.rs | 41 +- src/libstd/path/mod.rs | 22 +- src/libstd/path/posix.rs | 31 +- src/libstd/path/windows.rs | 26 +- src/libstd/rt/args.rs | 11 +- src/libstd/rt/backtrace.rs | 2 +- src/libstd/rt/unwind.rs | 2 +- src/libstd/rt/util.rs | 2 +- src/libstd/sys/common/mod.rs | 2 +- src/libstd/sys/common/net.rs | 12 +- src/libstd/sys/unix/backtrace.rs | 23 +- src/libstd/sys/unix/fs.rs | 48 +- src/libstd/sys/unix/mod.rs | 13 +- src/libstd/sys/unix/os.rs | 31 +- src/libstd/sys/unix/pipe.rs | 4 +- src/libstd/sys/unix/process.rs | 6 +- src/libstd/sys/unix/timer.rs | 2 +- src/libstd/sys/windows/backtrace.rs | 14 +- src/libstd/sys/windows/c.rs | 17 +- src/libstd/sys/windows/pipe.rs | 2 +- src/libstd/sys/windows/process.rs | 2 +- src/test/auxiliary/linkage-visibility.rs | 2 +- src/test/run-pass/c-stack-returning-int64.rs | 8 +- src/test/run-pass/const-str-ptr.rs | 4 - src/test/run-pass/foreign-fn-linkname.rs | 11 +- src/test/run-pass/rename-directory.rs | 23 +- src/test/run-pass/variadic-ffi.rs | 35 +- 58 files changed, 990 insertions(+), 1955 deletions(-) delete mode 100644 src/libstd/c_str.rs delete mode 100644 src/libstd/c_vec.rs create mode 100644 src/libstd/ffi/c_str.rs create mode 100644 src/libstd/ffi/mod.rs diff --git a/src/doc/guide-ffi.md b/src/doc/guide-ffi.md index b8808eaf57d93..7ee1c1a7032a5 100644 --- a/src/doc/guide-ffi.md +++ b/src/doc/guide-ffi.md @@ -451,7 +451,7 @@ them. ~~~no_run extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; use std::ptr; #[link(name = "readline")] @@ -460,11 +460,10 @@ extern { } fn main() { - "[my-awesome-shell] $".with_c_str(|buf| { - unsafe { rl_prompt = buf; } - // get a line, process it - unsafe { rl_prompt = ptr::null(); } - }); + let prompt = CString::from_slice(b"[my-awesome-shell] $"); + unsafe { rl_prompt = prompt.as_ptr(); } + // get a line, process it + unsafe { rl_prompt = ptr::null(); } } ~~~ @@ -509,23 +508,28 @@ to define a block for all windows systems, not just x86 ones. # Interoperability with foreign code -Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C -only if the `#[repr(C)]` attribute is applied to it. `#[repr(C, packed)]` can be used to lay out -struct members without padding. `#[repr(C)]` can also be applied to an enum. - -Rust's owned boxes (`Box`) use non-nullable pointers as handles which point to the contained -object. However, they should not be manually created because they are managed by internal -allocators. References can safely be assumed to be non-nullable pointers directly to the type. -However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so prefer -using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions about -them. - -Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and -`str` modules for working with C APIs. However, strings are not terminated with `\0`. If you need a -NUL-terminated string for interoperability with C, you should use the `c_str::to_c_str` function. - -The standard library includes type aliases and function definitions for the C standard library in -the `libc` module, and Rust links against `libc` and `libm` by default. +Rust guarantees that the layout of a `struct` is compatible with the platform's +representation in C only if the `#[repr(C)]` attribute is applied to it. +`#[repr(C, packed)]` can be used to lay out struct members without padding. +`#[repr(C)]` can also be applied to an enum. + +Rust's owned boxes (`Box`) use non-nullable pointers as handles which point +to the contained object. However, they should not be manually created because +they are managed by internal allocators. References can safely be assumed to be +non-nullable pointers directly to the type. However, breaking the borrow +checking or mutability rules is not guaranteed to be safe, so prefer using raw +pointers (`*`) if that's needed because the compiler can't make as many +assumptions about them. + +Vectors and strings share the same basic memory layout, and utilities are +available in the `vec` and `str` modules for working with C APIs. However, +strings are not terminated with `\0`. If you need a NUL-terminated string for +interoperability with C, you should use the `CString` type in the `std::ffi` +module. + +The standard library includes type aliases and function definitions for the C +standard library in the `libc` module, and Rust links against `libc` and `libm` +by default. # The "nullable pointer optimization" diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index e7451331908ae..b98efc6272a05 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -320,30 +320,6 @@ impl String { } } - /// Creates a `String` from a null-terminated `*const u8` buffer. - /// - /// This function is unsafe because we dereference memory until we find the - /// NUL character, which is not guaranteed to be present. Additionally, the - /// slice is not checked to see whether it contains valid UTF-8 - #[unstable = "just renamed from `mod raw`"] - pub unsafe fn from_raw_buf(buf: *const u8) -> String { - String::from_str(str::from_c_str(buf as *const i8)) - } - - /// Creates a `String` from a `*const u8` buffer of the given length. - /// - /// This function is unsafe because it blindly assumes the validity of the - /// pointer `buf` for `len` bytes of memory. This function will copy the - /// memory from `buf` into a new allocation (owned by the returned - /// `String`). - /// - /// This function is also unsafe because it does not validate that the - /// buffer is valid UTF-8 encoded data. - #[unstable = "just renamed from `mod raw`"] - pub unsafe fn from_raw_buf_len(buf: *const u8, len: uint) -> String { - String::from_utf8_unchecked(Vec::from_raw_buf(buf, len)) - } - /// Converts a vector of bytes to a new `String` without checking if /// it contains valid UTF-8. This is unsafe because it assumes that /// the UTF-8-ness of the vector has already been validated. diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index d069744f8da54..8fdd66f83cee4 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -190,7 +190,7 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str { /// # Panics /// /// This function will panic if the string pointed to by `s` is not valid UTF-8. -#[unstable = "may change location based on the outcome of the c_str module"] +#[deprecated = "use std::ffi::c_str_to_bytes + str::from_utf8"] pub unsafe fn from_c_str(s: *const i8) -> &'static str { let s = s as *const u8; let mut len = 0u; diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index aa1550ae5b874..a0c9da3ae6d49 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -21,15 +21,34 @@ #![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/")] -#![feature(phase, unboxed_closures)] +#![feature(phase, unboxed_closures, associated_types)] #[cfg(test)] #[phase(plugin, link)] extern crate log; extern crate libc; use libc::{c_void, size_t, c_int}; -use std::c_vec::CVec; +use std::ops::Deref; use std::ptr::Unique; +use std::slice; + +pub struct Bytes { + ptr: Unique, + len: uint, +} + +impl Deref for Bytes { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { slice::from_raw_mut_buf(&self.ptr.0, self.len) } + } +} + +impl Drop for Bytes { + fn drop(&mut self) { + unsafe { libc::free(self.ptr.0 as *mut _); } + } +} #[link(name = "miniz", kind = "static")] extern { @@ -52,7 +71,7 @@ static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal" static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum -fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { +fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option { unsafe { let mut outsz : size_t = 0; let res = tdefl_compress_mem_to_heap(bytes.as_ptr() as *const _, @@ -60,8 +79,8 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { &mut outsz, flags); if !res.is_null() { - let res = Unique(res); - Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0))) + let res = Unique(res as *mut u8); + Some(Bytes { ptr: res, len: outsz as uint }) } else { None } @@ -69,16 +88,16 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { } /// Compress a buffer, without writing any sort of header on the output. -pub fn deflate_bytes(bytes: &[u8]) -> Option> { +pub fn deflate_bytes(bytes: &[u8]) -> Option { deflate_bytes_internal(bytes, LZ_NORM) } /// Compress a buffer, using a header that zlib can understand. -pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option> { +pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option { deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) } -fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { +fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option { unsafe { let mut outsz : size_t = 0; let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _, @@ -86,8 +105,8 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { &mut outsz, flags); if !res.is_null() { - let res = Unique(res); - Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0))) + let res = Unique(res as *mut u8); + Some(Bytes { ptr: res, len: outsz as uint }) } else { None } @@ -95,12 +114,12 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { } /// Decompress a buffer, without parsing any sort of header on the input. -pub fn inflate_bytes(bytes: &[u8]) -> Option> { +pub fn inflate_bytes(bytes: &[u8]) -> Option { inflate_bytes_internal(bytes, 0) } /// Decompress a buffer that starts with a zlib header. -pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option> { +pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option { inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) } diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 2f4acaca4de4d..ec0b80c3a5342 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -23,8 +23,8 @@ use metadata::loader; use util::nodemap::{FnvHashMap, NodeMap}; use std::cell::RefCell; -use std::c_vec::CVec; use std::rc::Rc; +use flate::Bytes; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token::IdentInterner; @@ -36,7 +36,7 @@ use syntax::parse::token::IdentInterner; pub type cnum_map = FnvHashMap; pub enum MetadataBlob { - MetadataVec(CVec), + MetadataVec(Bytes), MetadataArchive(loader::ArchiveMetadata), } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index c18bd421b3b07..7c0645b4ca204 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -226,7 +226,7 @@ use syntax::codemap::Span; use syntax::diagnostic::SpanHandler; use util::fs; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cmp; use std::collections::{HashMap, HashSet}; use std::io::fs::PathExtensions; @@ -720,9 +720,8 @@ fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result Result Option { unsafe { - let ar = dst.with_c_str(|dst| { - ::LLVMRustOpenArchive(dst) - }); + let s = CString::from_slice(dst.as_vec()); + let ar = ::LLVMRustOpenArchive(s.as_ptr()); if ar.is_null() { None } else { @@ -45,9 +44,9 @@ impl ArchiveRO { pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> { unsafe { let mut size = 0 as libc::size_t; - let ptr = file.with_c_str(|file| { - ::LLVMRustArchiveReadSection(self.ptr, file, &mut size) - }); + let file = CString::from_slice(file.as_bytes()); + let ptr = ::LLVMRustArchiveReadSection(self.ptr, file.as_ptr(), + &mut size); if ptr.is_null() { None } else { diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 2ec5f37634afb..854ac5ff5c01c 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -47,7 +47,7 @@ pub use self::Visibility::*; pub use self::DiagnosticSeverity::*; pub use self::Linkage::*; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::RefCell; use std::{raw, mem}; use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char}; @@ -2114,10 +2114,9 @@ impl Drop for TargetData { } pub fn mk_target_data(string_rep: &str) -> TargetData { + let string_rep = CString::from_slice(string_rep.as_bytes()); TargetData { - lltd: string_rep.with_c_str(|buf| { - unsafe { LLVMCreateTargetData(buf) } - }) + lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) } } } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index c6488ec6638a3..f3e90c43a8414 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -20,7 +20,7 @@ use rustc::util::common::time; use libc; use flate; -use std::c_str::ToCStr; +use std::ffi::CString; use std::iter; use std::mem; use std::num::Int; @@ -139,9 +139,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, } // Internalize everything but the reachable symbols of the current module - let cstrs: Vec<::std::c_str::CString> = - reachable.iter().map(|s| s.to_c_str()).collect(); - let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect(); + let cstrs: Vec = reachable.iter().map(|s| { + CString::from_slice(s.as_bytes()) + }).collect(); + let arr: Vec<*const i8> = cstrs.iter().map(|c| c.as_ptr()).collect(); let ptr = arr.as_ptr(); unsafe { llvm::LLVMRustRunRestrictionPass(llmod, @@ -164,7 +165,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, unsafe { let pm = llvm::LLVMCreatePassManager(); llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod); - "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s)); + llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _); let builder = llvm::LLVMPassManagerBuilderCreate(); llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm, @@ -172,7 +173,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, /* RunInliner = */ True); llvm::LLVMPassManagerBuilderDispose(builder); - "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s)); + llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _); time(sess.time_passes(), "LTO passes", (), |()| llvm::LLVMRunPassManager(pm, llmod)); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 33011d9e35c10..089d7f737d3cf 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -22,7 +22,7 @@ use syntax::codemap; use syntax::diagnostic; use syntax::diagnostic::{Emitter, Handler, Level, mk_handler}; -use std::c_str::{ToCStr, CString}; +use std::ffi::{mod, CString}; use std::io::Command; use std::io::fs; use std::iter::Unfold; @@ -32,7 +32,7 @@ use std::mem; use std::sync::{Arc, Mutex}; use std::sync::mpsc::channel; use std::thread; -use libc::{c_uint, c_int, c_void}; +use libc::{mod, c_uint, c_int, c_void}; #[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] pub enum OutputType { @@ -49,8 +49,9 @@ pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! { if cstr == ptr::null() { handler.fatal(msg[]); } else { - let err = CString::new(cstr, true); - let err = String::from_utf8_lossy(err.as_bytes()); + let err = ffi::c_str_to_bytes(&cstr); + let err = String::from_utf8_lossy(err.as_slice()).to_string(); + libc::free(cstr as *mut _); handler.fatal(format!("{}: {}", msg[], err[])[]); @@ -66,13 +67,12 @@ pub fn write_output_file( output: &Path, file_type: llvm::FileType) { unsafe { - output.with_c_str(|output| { - let result = llvm::LLVMRustWriteOutputFile( - target, pm, m, output, file_type); - if !result { - llvm_err(handler, "could not write output".to_string()); - } - }) + let output = CString::from_slice(output.as_vec()); + let result = llvm::LLVMRustWriteOutputFile( + target, pm, m, output.as_ptr(), file_type); + if !result { + llvm_err(handler, "could not write output".to_string()); + } } } @@ -221,28 +221,25 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef { let triple = sess.target.target.llvm_target[]; let tm = unsafe { - triple.with_c_str(|t| { - let cpu = match sess.opts.cg.target_cpu { - Some(ref s) => s[], - None => sess.target.target.options.cpu[] - }; - cpu.with_c_str(|cpu| { - target_feature(sess).with_c_str(|features| { - llvm::LLVMRustCreateTargetMachine( - t, cpu, features, - code_model, - reloc_model, - opt_level, - true /* EnableSegstk */, - use_softfp, - no_fp_elim, - !any_library && reloc_model == llvm::RelocPIC, - ffunction_sections, - fdata_sections, - ) - }) - }) - }) + let triple = CString::from_slice(triple.as_bytes()); + let cpu = match sess.opts.cg.target_cpu { + Some(ref s) => s.as_slice(), + None => sess.target.target.options.cpu.as_slice() + }; + let cpu = CString::from_slice(cpu.as_bytes()); + let features = CString::from_slice(target_feature(sess).as_bytes()); + llvm::LLVMRustCreateTargetMachine( + triple.as_ptr(), cpu.as_ptr(), features.as_ptr(), + code_model, + reloc_model, + opt_level, + true /* EnableSegstk */, + use_softfp, + no_fp_elim, + !any_library && reloc_model == llvm::RelocPIC, + ffunction_sections, + fdata_sections, + ) }; if tm.is_null() { @@ -371,8 +368,9 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo match llvm::diagnostic::Diagnostic::unpack(info) { llvm::diagnostic::Optimization(opt) => { - let pass_name = CString::new(opt.pass_name, false); - let pass_name = pass_name.as_str().expect("got a non-UTF8 pass name from LLVM"); + let pass_name = str::from_utf8(ffi::c_str_to_bytes(&opt.pass_name)) + .ok() + .expect("got a non-UTF8 pass name from LLVM"); let enabled = match cgcx.remark { AllPasses => true, SomePasses(ref v) => v.iter().any(|s| *s == pass_name), @@ -416,9 +414,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_no_opt_bc { let ext = format!("{}.no-opt.bc", name_extra); - output_names.with_extension(ext[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } match config.opt_level { @@ -433,7 +431,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, // If we're verifying or linting, add them to the function pass // manager. let addpass = |&: pass: &str| { - pass.with_c_str(|s| llvm::LLVMRustAddPass(fpm, s)) + let pass = CString::from_slice(pass.as_bytes()); + llvm::LLVMRustAddPass(fpm, pass.as_ptr()) }; if !config.no_verify { assert!(addpass("verify")); } @@ -445,12 +444,11 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } for pass in config.passes.iter() { - pass.with_c_str(|s| { - if !llvm::LLVMRustAddPass(mpm, s) { - cgcx.handler.warn(format!("unknown pass {}, ignoring", - *pass)[]); - } - }) + let pass = CString::from_slice(pass.as_bytes()); + if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) { + cgcx.handler.warn(format!("unknown pass {}, ignoring", + pass).as_slice()); + } } // Finally, run the actual optimization passes @@ -470,9 +468,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_lto_bc { let name = format!("{}.lto.bc", name_extra); - output_names.with_extension(name[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(name.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } }, _ => {}, @@ -504,18 +502,18 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_bc { let ext = format!("{}.bc", name_extra); - output_names.with_extension(ext[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } time(config.time_passes, "codegen passes", (), |()| { if config.emit_ir { let ext = format!("{}.ll", name_extra); - output_names.with_extension(ext[]).with_c_str(|output| { - with_codegen(tm, llmod, config.no_builtins, |cpm| { - llvm::LLVMRustPrintModule(cpm, llmod, output); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + with_codegen(tm, llmod, config.no_builtins, |cpm| { + llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr()); }) } @@ -995,7 +993,7 @@ unsafe fn configure_llvm(sess: &Session) { let mut llvm_args = Vec::new(); { let mut add = |&mut : arg: &str| { - let s = arg.to_c_str(); + let s = CString::from_slice(arg.as_bytes()); llvm_args.push(s.as_ptr()); llvm_c_strs.push(s); }; @@ -1083,7 +1081,7 @@ unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef, match opt { llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => { - "mergefunc".with_c_str(|s| llvm::LLVMRustAddPass(mpm, s)); + llvm::LLVMRustAddPass(mpm, "mergefunc\0".as_ptr() as *const _); } _ => {} }; diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index 5597e112f76d1..f18d483f70328 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -20,9 +20,8 @@ use trans::expr; use trans::type_of; use trans::type_::Type; -use std::c_str::ToCStr; -use std::string::String; use syntax::ast; +use std::ffi::CString; use libc::{c_uint, c_char}; // Take an inline assembly expression and splat it out via LLVM @@ -121,18 +120,16 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) ast::AsmIntel => llvm::AD_Intel }; - let r = ia.asm.get().with_c_str(|a| { - constraints.with_c_str(|c| { - InlineAsmCall(bcx, - a, - c, - inputs[], + let asm = CString::from_slice(ia.asm.get().as_bytes()); + let constraints = CString::from_slice(constraints.as_bytes()); + let r = InlineAsmCall(bcx, + asm.as_ptr(), + constraints.as_ptr(), + inputs.as_slice(), output_type, ia.volatile, ia.alignstack, - dialect) - }) - }); + dialect); // Again, based on how many outputs we have if num_outputs == 1 { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 518042cf70889..d9c397d0c159e 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -88,11 +88,12 @@ use util::nodemap::NodeMap; use arena::TypedArena; use libc::{c_uint, uint64_t}; -use std::c_str::ToCStr; +use std::ffi::{mod, CString}; use std::cell::{Cell, RefCell}; use std::collections::HashSet; use std::mem; use std::rc::Rc; +use std::str; use std::{i8, i16, i32, i64}; use syntax::abi::{Rust, RustCall, RustIntrinsic, Abi}; use syntax::ast_util::local_def; @@ -187,11 +188,10 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, ty: Type, output: ty::FnOutput) -> ValueRef { - let llfn: ValueRef = name.with_c_str(|buf| { - unsafe { - llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf, ty.to_ref()) - } - }); + let buf = CString::from_slice(name.as_bytes()); + let llfn: ValueRef = unsafe { + llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref()) + }; // diverging functions may unwind, but can never return normally if output == ty::FnDiverging { @@ -334,9 +334,8 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, None => () } unsafe { - let c = name.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf) - }); + let buf = CString::from_slice(name.as_bytes()); + let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr()); // Thread-local statics in some other crate need to *always* be linked // against in a thread-local fashion, so we need to be sure to apply the // thread-local attribute locally if it was present remotely. If we @@ -475,15 +474,17 @@ pub fn set_always_inline(f: ValueRef) { } pub fn set_split_stack(f: ValueRef) { - "split-stack".with_c_str(|buf| { - unsafe { llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); } - }) + unsafe { + llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, + "split-stack\0".as_ptr() as *const _); + } } pub fn unset_split_stack(f: ValueRef) { - "split-stack".with_c_str(|buf| { - unsafe { llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); } - }) + unsafe { + llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, + "split-stack\0".as_ptr() as *const _); + } } // Double-check that we never ask LLVM to declare the same symbol twice. It @@ -537,11 +538,8 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Structural comparison: a rather involved form of glue. pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) { if cx.sess().opts.cg.save_temps { - s.with_c_str(|buf| { - unsafe { - llvm::LLVMSetValueName(v, buf) - } - }) + let buf = CString::from_slice(s.as_bytes()); + unsafe { llvm::LLVMSetValueName(v, buf.as_ptr()) } } } @@ -2645,11 +2643,10 @@ pub fn create_entry_wrapper(ccx: &CrateContext, unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) } } - let llbb = "top".with_c_str(|buf| { - unsafe { - llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, buf) - } - }); + let llbb = unsafe { + llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, + "top\0".as_ptr() as *const _) + }; let bld = ccx.raw_builder(); unsafe { llvm::LLVMPositionBuilderAtEnd(bld, llbb); @@ -2670,9 +2667,9 @@ pub fn create_entry_wrapper(ccx: &CrateContext, }; let args = { - let opaque_rust_main = "rust_main".with_c_str(|buf| { - llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p(ccx).to_ref(), buf) - }); + let opaque_rust_main = llvm::LLVMBuildPointerCast(bld, + rust_main, Type::i8p(ccx).to_ref(), + "rust_main\0".as_ptr() as *const _); vec!( opaque_rust_main, @@ -2779,9 +2776,9 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { format!("Illegal null byte in export_name \ value: `{}`", sym)[]); } - let g = sym.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty, buf) - }); + let buf = CString::from_slice(sym.as_bytes()); + let g = llvm::LLVMAddGlobal(ccx.llmod(), llty, + buf.as_ptr()); if attr::contains_name(i.attrs[], "thread_local") { @@ -2823,9 +2820,8 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { sect.get())[]); } unsafe { - sect.get().with_c_str(|buf| { - llvm::LLVMSetSection(v, buf); - }) + let buf = CString::from_slice(sect.get().as_bytes()); + llvm::LLVMSetSection(v, buf.as_ptr()); } }, None => () @@ -2992,17 +2988,16 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec { let name = format!("rust_metadata_{}_{}", cx.link_meta().crate_name, cx.link_meta().crate_hash); - let llglobal = name.with_c_str(|buf| { - unsafe { - llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf) - } - }); + let buf = CString::from_vec(name.into_bytes()); + let llglobal = unsafe { + llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), + buf.as_ptr()) + }; unsafe { llvm::LLVMSetInitializer(llglobal, llconst); let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx); - name.with_c_str(|buf| { - llvm::LLVMSetSection(llglobal, buf) - }); + let name = CString::from_slice(name.as_bytes()); + llvm::LLVMSetSection(llglobal, name.as_ptr()) } return metadata; } @@ -3010,8 +3005,6 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec { /// Find any symbols that are defined in one compilation unit, but not declared /// in any other compilation unit. Give these symbols internal linkage. fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { - use std::c_str::CString; - unsafe { let mut declared = HashSet::new(); @@ -3041,7 +3034,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { continue } - let name = CString::new(llvm::LLVMGetValueName(val), false); + let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val)) + .to_vec(); declared.insert(name); } } @@ -3057,9 +3051,10 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { continue } - let name = CString::new(llvm::LLVMGetValueName(val), false); + let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val)) + .to_vec(); if !declared.contains(&name) && - !reachable.contains(name.as_str().unwrap()) { + !reachable.contains(str::from_utf8(name.as_slice()).unwrap()) { llvm::SetLinkage(val, llvm::InternalLinkage); } } diff --git a/src/librustc_trans/trans/builder.rs b/src/librustc_trans/trans/builder.rs index 97f0b92a290f8..e09d36ddae923 100644 --- a/src/librustc_trans/trans/builder.rs +++ b/src/librustc_trans/trans/builder.rs @@ -20,7 +20,8 @@ use trans::machine::llalign_of_pref; use trans::type_::Type; use util::nodemap::FnvHashMap; use libc::{c_uint, c_char}; -use std::c_str::ToCStr; + +use std::ffi::CString; use syntax::codemap::Span; pub struct Builder<'a, 'tcx: 'a> { @@ -429,9 +430,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if name.is_empty() { llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname()) } else { - name.with_c_str(|c| { - llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c) - }) + let name = CString::from_slice(name.as_bytes()); + llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), + name.as_ptr()) } } } @@ -774,12 +775,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let comment_text = format!("{} {}", "#", sanitized.replace("\n", "\n\t# ")); self.count_insn("inlineasm"); - let asm = comment_text.with_c_str(|c| { - unsafe { - llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(), - c, noname(), False, False) - } - }); + let comment_text = CString::from_vec(comment_text.into_bytes()); + let asm = unsafe { + llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(), + comment_text.as_ptr(), noname(), False, + False) + }; self.call(asm, &[], None); } } @@ -926,9 +927,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let bb: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder); let fn_: ValueRef = llvm::LLVMGetBasicBlockParent(bb); let m: ModuleRef = llvm::LLVMGetGlobalParent(fn_); - let t: ValueRef = "llvm.trap".with_c_str(|buf| { - llvm::LLVMGetNamedFunction(m, buf) - }); + let p = "llvm.trap\0".as_ptr(); + let t: ValueRef = llvm::LLVMGetNamedFunction(m, p as *const _); assert!((t as int != 0)); let args: &[ValueRef] = &[]; self.count_insn("trap"); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index e8dee19ed54c1..094f98e988aad 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -44,7 +44,7 @@ use util::nodemap::{FnvHashMap, NodeMap}; use arena::TypedArena; use libc::{c_uint, c_char}; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::{Cell, RefCell}; use std::vec::Vec; use syntax::ast::Ident; @@ -401,9 +401,8 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { if self.llreturn.get().is_none() { self.llreturn.set(Some(unsafe { - "return".with_c_str(|buf| { - llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, buf) - }) + llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, + "return\0".as_ptr() as *const _) })) } @@ -429,11 +428,10 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { opt_node_id: Option) -> Block<'a, 'tcx> { unsafe { - let llbb = name.with_c_str(|buf| { - llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), - self.llfn, - buf) - }); + let name = CString::from_slice(name.as_bytes()); + let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), + self.llfn, + name.as_ptr()); BlockS::new(llbb, is_lpad, opt_node_id, self) } } @@ -708,7 +706,8 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { pub fn C_floating(s: &str, t: Type) -> ValueRef { unsafe { - s.with_c_str(|buf| llvm::LLVMConstRealOfString(t.to_ref(), buf)) + let s = CString::from_slice(s.as_bytes()); + llvm::LLVMConstRealOfString(t.to_ref(), s.as_ptr()) } } @@ -789,9 +788,8 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va !null_terminated as Bool); let gsym = token::gensym("str"); - let g = format!("str{}", gsym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf) - }); + let buf = CString::from_vec(format!("str{}", gsym.uint()).into_bytes()); + let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr()); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); @@ -815,9 +813,10 @@ pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef { let lldata = C_bytes(cx, data); let gsym = token::gensym("binary"); - let g = format!("binary{}", gsym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(lldata).to_ref(), buf) - }); + let name = format!("binary{}", gsym.uint()); + let name = CString::from_vec(name.into_bytes()); + let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(lldata).to_ref(), + name.as_ptr()); llvm::LLVMSetInitializer(g, lldata); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index b17e852d7cbc4..9432fa8bd3d59 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -24,7 +24,6 @@ use middle::subst::Substs; use middle::ty::{self, Ty}; use util::ppaux::{Repr, ty_to_string}; -use std::c_str::ToCStr; use std::iter::repeat; use libc::c_uint; use syntax::{ast, ast_util}; @@ -103,9 +102,8 @@ fn const_vec(cx: &CrateContext, e: &ast::Expr, pub fn const_addr_of(cx: &CrateContext, cv: ValueRef, mutbl: ast::Mutability) -> ValueRef { unsafe { - let gv = "const".with_c_str(|name| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(), name) - }); + let gv = llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(), + "const\0".as_ptr() as *const _); llvm::LLVMSetInitializer(gv, cv); llvm::LLVMSetGlobalConstant(gv, if mutbl == ast::MutImmutable {True} else {False}); diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index e5a0e2e9234d5..f974a6faf4c19 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -29,8 +29,8 @@ use util::ppaux::Repr; use util::sha2::Sha256; use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; +use std::ffi::CString; use std::cell::{Cell, RefCell}; -use std::c_str::ToCStr; use std::ptr; use std::rc::Rc; use syntax::ast; @@ -221,21 +221,16 @@ impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> { unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { let llcx = llvm::LLVMContextCreate(); - let llmod = mod_name.with_c_str(|buf| { - llvm::LLVMModuleCreateWithNameInContext(buf, llcx) - }); - sess.target - .target - .data_layout - .with_c_str(|buf| { - llvm::LLVMSetDataLayout(llmod, buf); - }); - sess.target - .target - .llvm_target - .with_c_str(|buf| { - llvm::LLVMRustSetNormalizedTarget(llmod, buf); - }); + let mod_name = CString::from_slice(mod_name.as_bytes()); + let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); + + let data_layout = sess.target.target.data_layout.as_slice(); + let data_layout = CString::from_slice(data_layout.as_bytes()); + llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); + + let llvm_target = sess.target.target.llvm_target.as_slice(); + let llvm_target = CString::from_slice(llvm_target.as_bytes()); + llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); (llcx, llmod) } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 916fcbfe13ef7..a55953a882f03 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -207,7 +207,7 @@ use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet}; use util::ppaux; use libc::c_uint; -use std::c_str::{CString, ToCStr}; +use std::ffi::CString; use std::cell::{Cell, RefCell}; use std::ptr; use std::rc::{Rc, Weak}; @@ -760,14 +760,15 @@ pub fn finalize(cx: &CrateContext) { // for OS X to understand. For more info see #11352 // This can be overridden using --llvm-opts -dwarf-version,N. if cx.sess().target.target.options.is_like_osx { - "Dwarf Version".with_c_str( - |s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, 2)); + llvm::LLVMRustAddModuleFlag(cx.llmod(), + "Dwarf Version\0".as_ptr() as *const _, + 2) } // Prevent bitcode readers from deleting the debug info. - "Debug Info Version".with_c_str( - |s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, - llvm::LLVMRustDebugMetadataVersion)); + let ptr = "Debug Info Version\0".as_ptr(); + llvm::LLVMRustAddModuleFlag(cx.llmod(), ptr as *const _, + llvm::LLVMRustDebugMetadataVersion); }; } @@ -829,22 +830,20 @@ pub fn create_global_var_metadata(cx: &CrateContext, namespace_node.mangled_name_of_contained_item(var_name[]); let var_scope = namespace_node.scope; - var_name.with_c_str(|var_name| { - linkage_name.with_c_str(|linkage_name| { - unsafe { - llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx), - var_scope, - var_name, - linkage_name, - file_metadata, - line_number, - type_metadata, - is_local_to_unit, - global, - ptr::null_mut()); - } - }) - }); + let var_name = CString::from_slice(var_name.as_bytes()); + let linkage_name = CString::from_slice(linkage_name.as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx), + var_scope, + var_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + line_number, + type_metadata, + is_local_to_unit, + global, + ptr::null_mut()); + } } /// Creates debug information for the given local variable. @@ -1388,28 +1387,26 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let is_local_to_unit = is_node_local_to_unit(cx, fn_ast_id); - let fn_metadata = function_name.with_c_str(|function_name| { - linkage_name.with_c_str(|linkage_name| { - unsafe { - llvm::LLVMDIBuilderCreateFunction( - DIB(cx), - containing_scope, - function_name, - linkage_name, - file_metadata, - loc.line as c_uint, - function_type_metadata, - is_local_to_unit, - true, - scope_line as c_uint, - FlagPrototyped as c_uint, - cx.sess().opts.optimize != config::No, - llfn, - template_parameters, - ptr::null_mut()) - } - }) - }); + let function_name = CString::from_slice(function_name.as_bytes()); + let linkage_name = CString::from_slice(linkage_name.as_bytes()); + let fn_metadata = unsafe { + llvm::LLVMDIBuilderCreateFunction( + DIB(cx), + containing_scope, + function_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + loc.line as c_uint, + function_type_metadata, + is_local_to_unit, + true, + scope_line as c_uint, + FlagPrototyped as c_uint, + cx.sess().opts.optimize != config::No, + llfn, + template_parameters, + ptr::null_mut()) + }; let scope_map = create_scope_map(cx, fn_decl.inputs.as_slice(), @@ -1514,19 +1511,18 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let ident = special_idents::type_self; - let param_metadata = token::get_ident(ident).get() - .with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateTemplateTypeParameter( - DIB(cx), - file_metadata, - name, - actual_self_type_metadata, - ptr::null_mut(), - 0, - 0) - } - }); + let ident = token::get_ident(ident); + let name = CString::from_slice(ident.get().as_bytes()); + let param_metadata = unsafe { + llvm::LLVMDIBuilderCreateTemplateTypeParameter( + DIB(cx), + file_metadata, + name.as_ptr(), + actual_self_type_metadata, + ptr::null_mut(), + 0, + 0) + }; template_params.push(param_metadata); } @@ -1549,19 +1545,18 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Again, only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo == FullDebugInfo { let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP); - let param_metadata = token::get_ident(ident).get() - .with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateTemplateTypeParameter( - DIB(cx), - file_metadata, - name, - actual_type_metadata, - ptr::null_mut(), - 0, - 0) - } - }); + let ident = token::get_ident(ident); + let name = CString::from_slice(ident.get().as_bytes()); + let param_metadata = unsafe { + llvm::LLVMDIBuilderCreateTemplateTypeParameter( + DIB(cx), + file_metadata, + name.as_ptr(), + actual_type_metadata, + ptr::null_mut(), + 0, + 0) + }; template_params.push(param_metadata); } } @@ -1606,19 +1601,19 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { } else { match abs_path.path_relative_from(work_dir) { Some(ref p) if p.is_relative() => { - // prepend "./" if necessary - let dotdot = b".."; - let prefix = [dotdot[0], ::std::path::SEP_BYTE]; - let mut path_bytes = p.as_vec().to_vec(); - - if path_bytes.slice_to(2) != prefix && - path_bytes.slice_to(2) != dotdot { - path_bytes.insert(0, prefix[0]); - path_bytes.insert(1, prefix[1]); - } - - path_bytes.to_c_str() + // prepend "./" if necessary + let dotdot = b".."; + let prefix: &[u8] = &[dotdot[0], ::std::path::SEP_BYTE]; + let mut path_bytes = p.as_vec().to_vec(); + + if path_bytes.slice_to(2) != prefix && + path_bytes.slice_to(2) != dotdot { + path_bytes.insert(0, prefix[0]); + path_bytes.insert(1, prefix[1]); } + + CString::from_vec(path_bytes) + } _ => fallback_path(cx) } } @@ -1630,29 +1625,25 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { (option_env!("CFG_VERSION")).expect("CFG_VERSION")); let compile_unit_name = compile_unit_name.as_ptr(); - return work_dir.as_vec().with_c_str(|work_dir| { - producer.with_c_str(|producer| { - "".with_c_str(|flags| { - "".with_c_str(|split_name| { - unsafe { - llvm::LLVMDIBuilderCreateCompileUnit( - debug_context(cx).builder, - DW_LANG_RUST, - compile_unit_name, - work_dir, - producer, - cx.sess().opts.optimize != config::No, - flags, - 0, - split_name) - } - }) - }) - }) - }); + let work_dir = CString::from_slice(work_dir.as_vec()); + let producer = CString::from_slice(producer.as_bytes()); + let flags = "\0"; + let split_name = "\0"; + return unsafe { + llvm::LLVMDIBuilderCreateCompileUnit( + debug_context(cx).builder, + DW_LANG_RUST, + compile_unit_name, + work_dir.as_ptr(), + producer.as_ptr(), + cx.sess().opts.optimize != config::No, + flags.as_ptr() as *const _, + 0, + split_name.as_ptr() as *const _) + }; fn fallback_path(cx: &CrateContext) -> CString { - cx.link_meta().crate_name.to_c_str() + CString::from_slice(cx.link_meta().crate_name.as_bytes()) } } @@ -1678,42 +1669,41 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, CapturedVariable => (0, DW_TAG_auto_variable) }; - let (var_alloca, var_metadata) = name.get().with_c_str(|name| { - match variable_access { - DirectVariable { alloca } => ( - alloca, - unsafe { - llvm::LLVMDIBuilderCreateLocalVariable( - DIB(cx), - dwarf_tag, - scope_metadata, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - cx.sess().opts.optimize != config::No, - 0, - argument_index) - } - ), - IndirectVariable { alloca, address_operations } => ( - alloca, - unsafe { - llvm::LLVMDIBuilderCreateComplexVariable( - DIB(cx), - dwarf_tag, - scope_metadata, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - address_operations.as_ptr(), - address_operations.len() as c_uint, - argument_index) - } - ) - } - }); + let name = CString::from_slice(name.get().as_bytes()); + let (var_alloca, var_metadata) = match variable_access { + DirectVariable { alloca } => ( + alloca, + unsafe { + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + cx.sess().opts.optimize != config::No, + 0, + argument_index) + } + ), + IndirectVariable { alloca, address_operations } => ( + alloca, + unsafe { + llvm::LLVMDIBuilderCreateComplexVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + address_operations.as_ptr(), + address_operations.len() as c_uint, + argument_index) + } + ) + }; set_debug_location(cx, DebugLocation::new(scope_metadata, loc.line, @@ -1758,14 +1748,12 @@ fn file_metadata(cx: &CrateContext, full_path: &str) -> DIFile { full_path }; - let file_metadata = - file_name.with_c_str(|file_name| { - work_dir.with_c_str(|work_dir| { - unsafe { - llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir) - } - }) - }); + let file_name = CString::from_slice(file_name.as_bytes()); + let work_dir = CString::from_slice(work_dir.as_bytes()); + let file_metadata = unsafe { + llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name.as_ptr(), + work_dir.as_ptr()) + }; let mut created_files = debug_context(cx).created_files.borrow_mut(); created_files.insert(full_path.to_string(), file_metadata); @@ -1793,16 +1781,14 @@ fn scope_metadata(fcx: &FunctionContext, } fn diverging_type_metadata(cx: &CrateContext) -> DIType { - "!".with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), - name, - bytes_to_bits(0), - bytes_to_bits(0), - DW_ATE_unsigned) - } - }) + unsafe { + llvm::LLVMDIBuilderCreateBasicType( + DIB(cx), + "!\0".as_ptr() as *const _, + bytes_to_bits(0), + bytes_to_bits(0), + DW_ATE_unsigned) + } } fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, @@ -1838,16 +1824,15 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let llvm_type = type_of::type_of(cx, t); let (size, align) = size_and_align_of(cx, llvm_type); - let ty_metadata = name.with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), - name, - bytes_to_bits(size), - bytes_to_bits(align), - encoding) - } - }); + let name = CString::from_slice(name.as_bytes()); + let ty_metadata = unsafe { + llvm::LLVMDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr(), + bytes_to_bits(size), + bytes_to_bits(align), + encoding) + }; return ty_metadata; } @@ -1859,16 +1844,15 @@ fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let pointer_llvm_type = type_of::type_of(cx, pointer_type); let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type); let name = compute_debuginfo_type_name(cx, pointer_type, false); - let ptr_metadata = name.with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreatePointerType( - DIB(cx), - pointee_type_metadata, - bytes_to_bits(pointer_size), - bytes_to_bits(pointer_align), - name) - } - }); + let name = CString::from_slice(name.as_bytes()); + let ptr_metadata = unsafe { + llvm::LLVMDIBuilderCreatePointerType( + DIB(cx), + pointee_type_metadata, + bytes_to_bits(pointer_size), + bytes_to_bits(pointer_align), + name.as_ptr()) + }; return ptr_metadata; } @@ -2478,14 +2462,14 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let enumerators_metadata: Vec = variants .iter() .map(|v| { - token::get_name(v.name).get().with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateEnumerator( - DIB(cx), - name, - v.disr_val as u64) - } - }) + let token = token::get_name(v.name); + let name = CString::from_slice(token.get().as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr(), + v.disr_val as u64) + } }) .collect(); @@ -2509,20 +2493,19 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, codemap::DUMMY_SP); let discriminant_name = get_enum_discriminant_name(cx, enum_def_id); - let discriminant_type_metadata = discriminant_name.get().with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateEnumerationType( - DIB(cx), - containing_scope, - name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(discriminant_size), - bytes_to_bits(discriminant_align), - create_DIArray(DIB(cx), enumerators_metadata[]), - discriminant_base_type_metadata) - } - }); + let name = CString::from_slice(discriminant_name.get().as_bytes()); + let discriminant_type_metadata = unsafe { + llvm::LLVMDIBuilderCreateEnumerationType( + DIB(cx), + containing_scope, + name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(discriminant_size), + bytes_to_bits(discriminant_align), + create_DIArray(DIB(cx), enumerators_metadata.as_slice()), + discriminant_base_type_metadata) + }; debug_context(cx).created_enum_disr_types .borrow_mut() @@ -2553,24 +2536,22 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, .borrow() .get_unique_type_id_as_string(unique_type_id); - let enum_metadata = enum_name.with_c_str(|enum_name| { - unique_type_id_str.with_c_str(|unique_type_id_str| { - unsafe { - llvm::LLVMDIBuilderCreateUnionType( - DIB(cx), - containing_scope, - enum_name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(enum_type_size), - bytes_to_bits(enum_type_align), - 0, // Flags - ptr::null_mut(), - 0, // RuntimeLang - unique_type_id_str) - } - }) - }); + let enum_name = CString::from_slice(enum_name.as_bytes()); + let unique_type_id_str = CString::from_slice(unique_type_id_str.as_bytes()); + let enum_metadata = unsafe { + llvm::LLVMDIBuilderCreateUnionType( + DIB(cx), + containing_scope, + enum_name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(enum_type_size), + bytes_to_bits(enum_type_align), + 0, // Flags + ptr::null_mut(), + 0, // RuntimeLang + unique_type_id_str.as_ptr()) + }; return create_and_register_recursive_type_forward_declaration( cx, @@ -2681,21 +2662,20 @@ fn set_members_of_composite_type(cx: &CrateContext, ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i) }; - member_description.name.with_c_str(|member_name| { - unsafe { - llvm::LLVMDIBuilderCreateMemberType( - DIB(cx), - composite_type_metadata, - member_name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(member_size), - bytes_to_bits(member_align), - bytes_to_bits(member_offset), - member_description.flags, - member_description.type_metadata) - } - }) + let member_name = CString::from_slice(member_description.name.as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateMemberType( + DIB(cx), + composite_type_metadata, + member_name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(member_size), + bytes_to_bits(member_align), + bytes_to_bits(member_offset), + member_description.flags, + member_description.type_metadata) + } }) .collect(); @@ -2719,30 +2699,28 @@ fn create_struct_stub(cx: &CrateContext, let unique_type_id_str = debug_context(cx).type_map .borrow() .get_unique_type_id_as_string(unique_type_id); + let name = CString::from_slice(struct_type_name.as_bytes()); + let unique_type_id = CString::from_slice(unique_type_id_str.as_bytes()); let metadata_stub = unsafe { - struct_type_name.with_c_str(|name| { - unique_type_id_str.with_c_str(|unique_type_id| { - // LLVMDIBuilderCreateStructType() wants an empty array. A null - // pointer will lead to hard to trace and debug LLVM assertions - // later on in llvm/lib/IR/Value.cpp. - let empty_array = create_DIArray(DIB(cx), &[]); - - llvm::LLVMDIBuilderCreateStructType( - DIB(cx), - containing_scope, - name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(struct_size), - bytes_to_bits(struct_align), - 0, - ptr::null_mut(), - empty_array, - 0, - ptr::null_mut(), - unique_type_id) - }) - }) + // LLVMDIBuilderCreateStructType() wants an empty array. A null + // pointer will lead to hard to trace and debug LLVM assertions + // later on in llvm/lib/IR/Value.cpp. + let empty_array = create_DIArray(DIB(cx), &[]); + + llvm::LLVMDIBuilderCreateStructType( + DIB(cx), + containing_scope, + name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(struct_size), + bytes_to_bits(struct_align), + 0, + ptr::null_mut(), + empty_array, + 0, + ptr::null_mut(), + unique_type_id.as_ptr()) }; return metadata_stub; @@ -4079,18 +4057,18 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc ptr::null_mut() }; let namespace_name = token::get_name(name); - let scope = namespace_name.get().with_c_str(|namespace_name| { - unsafe { - llvm::LLVMDIBuilderCreateNameSpace( - DIB(cx), - parent_scope, - namespace_name, - // cannot reconstruct file ... - ptr::null_mut(), - // ... or line information, but that's not so important. - 0) - } - }); + let namespace_name = CString::from_slice(namespace_name + .get().as_bytes()); + let scope = unsafe { + llvm::LLVMDIBuilderCreateNameSpace( + DIB(cx), + parent_scope, + namespace_name.as_ptr(), + // cannot reconstruct file ... + ptr::null_mut(), + // ... or line information, but that's not so important. + 0) + }; let node = Rc::new(NamespaceTreeNode { name: name, @@ -4128,7 +4106,7 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc llvm::ValueRef { - let section_var_name = b"__rustc_debug_gdb_scripts_section__".to_c_str(); + let section_var_name = b"__rustc_debug_gdb_scripts_section__\0"; let section_var = unsafe { - llvm::LLVMGetNamedGlobal(ccx.llmod(), section_var_name.as_ptr()) + llvm::LLVMGetNamedGlobal(ccx.llmod(), + section_var_name.as_ptr() as *const _) }; if section_var == ptr::null_mut() { - let section_name = b".debug_gdb_scripts".to_c_str(); + let section_name = b".debug_gdb_scripts\0"; let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0"; unsafe { @@ -4160,8 +4139,9 @@ fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) section_contents.len() as u64); let section_var = llvm::LLVMAddGlobal(ccx.llmod(), llvm_type.to_ref(), - section_var_name.as_ptr()); - llvm::LLVMSetSection(section_var, section_name.as_ptr()); + section_var_name.as_ptr() + as *const _); + llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddr(section_var, llvm::True); diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index a4cfec791d817..1c9be6ae4a8ba 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -24,9 +24,10 @@ use trans::type_::Type; use trans::type_of::*; use trans::type_of; use middle::ty::{self, Ty}; -use middle::subst::{Substs}; +use middle::subst::Substs; + +use std::ffi::CString; use std::cmp; -use std::c_str::ToCStr; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; @@ -132,9 +133,9 @@ pub fn register_static(ccx: &CrateContext, }; unsafe { // Declare a symbol `foo` with the desired linkage. - let g1 = ident.get().with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), buf) - }); + let buf = CString::from_slice(ident.get().as_bytes()); + let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), + buf.as_ptr()); llvm::SetLinkage(g1, linkage); // Declare an internal global `extern_with_linkage_foo` which @@ -145,9 +146,9 @@ pub fn register_static(ccx: &CrateContext, // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); real_name.push_str(ident.get()); - let g2 = real_name.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf) - }); + let real_name = CString::from_vec(real_name.into_bytes()); + let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), + real_name.as_ptr()); llvm::SetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); g2 @@ -155,9 +156,8 @@ pub fn register_static(ccx: &CrateContext, } None => unsafe { // Generate an external declaration. - ident.get().with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf) - }) + let buf = CString::from_slice(ident.get().as_bytes()); + llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf.as_ptr()) } } } @@ -606,9 +606,9 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // return r; // } - let the_block = - "the block".with_c_str( - |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, s)); + let ptr = "the block\0".as_ptr(); + let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, + ptr as *const _); let builder = ccx.builder(); builder.position_at_end(the_block); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index c049704181354..2525220c57021 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -40,8 +40,8 @@ use util::ppaux::{ty_to_short_str, Repr}; use util::ppaux; use arena::TypedArena; -use std::c_str::ToCStr; use libc::c_uint; +use std::ffi::CString; use syntax::ast; use syntax::parse::token; @@ -498,11 +498,11 @@ pub fn declare_tydesc<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) let llalign = llalign_of(ccx, llty); let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc"); debug!("+++ declare_tydesc {} {}", ppaux::ty_to_string(ccx.tcx(), t), name); - let gvar = name.with_c_str(|buf| { - unsafe { - llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), buf) - } - }); + let buf = CString::from_slice(name.as_bytes()); + let gvar = unsafe { + llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), + buf.as_ptr()) + }; note_unique_llvm_symbol(ccx, name); let ty_name = token::intern_and_get_ident( diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index c13516134c20c..dec4524e67665 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -34,7 +34,7 @@ use middle::ty::{self, Ty}; use middle::ty::MethodCall; use util::ppaux::Repr; -use std::c_str::ToCStr; +use std::ffi::CString; use std::rc::Rc; use syntax::abi::{Rust, RustCall}; use syntax::parse::token; @@ -742,9 +742,9 @@ pub fn make_vtable>(ccx: &CrateContext, unsafe { let tbl = C_struct(ccx, components[], false); let sym = token::gensym("vtable"); - let vt_gvar = format!("vtable{}", sym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(), buf) - }); + let buf = CString::from_vec(format!("vtable{}", sym.uint()).into_bytes()); + let vt_gvar = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(), + buf.as_ptr()); llvm::LLVMSetInitializer(vt_gvar, tbl); llvm::LLVMSetGlobalConstant(vt_gvar, llvm::True); llvm::SetLinkage(vt_gvar, llvm::InternalLinkage); diff --git a/src/librustc_trans/trans/type_.rs b/src/librustc_trans/trans/type_.rs index 5b76f5bb8270e..3785c2fb9bc54 100644 --- a/src/librustc_trans/trans/type_.rs +++ b/src/librustc_trans/trans/type_.rs @@ -19,7 +19,7 @@ use util::nodemap::FnvHashMap; use syntax::ast; -use std::c_str::ToCStr; +use std::ffi::CString; use std::mem; use std::cell::RefCell; use std::iter::repeat; @@ -157,7 +157,8 @@ impl Type { } pub fn named_struct(ccx: &CrateContext, name: &str) -> Type { - ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ccx.llcx(), s))) + let name = CString::from_slice(name.as_bytes()); + ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr())) } pub fn empty_struct(ccx: &CrateContext) -> Type { diff --git a/src/librustdoc/flock.rs b/src/librustdoc/flock.rs index 0f0dbf6a24dff..dcc90117d2660 100644 --- a/src/librustdoc/flock.rs +++ b/src/librustdoc/flock.rs @@ -20,8 +20,8 @@ pub use self::imp::Lock; #[cfg(unix)] mod imp { + use std::ffi::CString; use libc; - use std::c_str::ToCStr; #[cfg(target_os = "linux")] mod os { @@ -111,9 +111,11 @@ mod imp { impl Lock { pub fn new(p: &Path) -> Lock { - let fd = p.with_c_str(|s| unsafe { - libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU) - }); + let buf = CString::from_slice(p.as_vec()); + let fd = unsafe { + libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT, + libc::S_IRWXU) + }; assert!(fd > 0); let flock = os::flock { l_start: 0, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 9d003eca27f3d..3b9265cf56976 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -29,7 +29,7 @@ use libc; use std::ascii::AsciiExt; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::{RefCell, Cell}; use std::collections::HashMap; use std::fmt; @@ -215,7 +215,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { let id = id.as_ref().map(|a| a.as_slice()); s.push_str(highlight::highlight(text.as_slice(), None, id) .as_slice()); - let output = s.to_c_str(); + let output = CString::from_vec(s.into_bytes()); hoedown_buffer_puts(ob, output.as_ptr()); }) } @@ -224,15 +224,16 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer, level: libc::c_int, opaque: *mut libc::c_void) { // hoedown does this, we may as well too - "\n".with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); + unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); } // Extract the text provided let s = if text.is_null() { "".to_string() } else { - unsafe { - String::from_raw_buf_len((*text).data, (*text).size as uint) - } + let s = unsafe { + slice::from_raw_buf(&(*text).data, (*text).size as uint) + }; + str::from_utf8(s).unwrap().to_string() }; // Transform the contents of the header into a hyphenated string @@ -273,7 +274,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { format!("{} ", sec) }); - text.with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); + let text = CString::from_vec(text.into_bytes()); + unsafe { hoedown_buffer_puts(ob, text.as_ptr()) } } reset_headers(); diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs deleted file mode 100644 index 9c96a9cac7831..0000000000000 --- a/src/libstd/c_str.rs +++ /dev/null @@ -1,857 +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. - -//! C-string manipulation and management -//! -//! This modules provides the basic methods for creating and manipulating -//! null-terminated strings for use with FFI calls (back to C). Most C APIs require -//! that the string being passed to them is null-terminated, and by default rust's -//! string types are *not* null terminated. -//! -//! The other problem with translating Rust strings to C strings is that Rust -//! strings can validly contain a null-byte in the middle of the string (0 is a -//! valid Unicode codepoint). This means that not all Rust strings can actually be -//! translated to C strings. -//! -//! # Creation of a C string -//! -//! A C string is managed through the `CString` type defined in this module. It -//! "owns" the internal buffer of characters and will automatically deallocate the -//! buffer when the string is dropped. The `ToCStr` trait is implemented for `&str` -//! and `&[u8]`, but the conversions can fail due to some of the limitations -//! explained above. -//! -//! This also means that currently whenever a C string is created, an allocation -//! must be performed to place the data elsewhere (the lifetime of the C string is -//! not tied to the lifetime of the original string/data buffer). If C strings are -//! heavily used in applications, then caching may be advisable to prevent -//! unnecessary amounts of allocations. -//! -//! Be carefull to remember that the memory is managed by C allocator API and not -//! by Rust allocator API. -//! That means that the CString pointers should be freed with C allocator API -//! if you intend to do that on your own, as the behaviour if you free them with -//! Rust's allocator API is not well defined -//! -//! An example of creating and using a C string would be: -//! -//! ```rust -//! extern crate libc; -//! -//! use std::c_str::ToCStr; -//! -//! extern { -//! fn puts(s: *const libc::c_char); -//! } -//! -//! fn main() { -//! let my_string = "Hello, world!"; -//! -//! // Allocate the C string with an explicit local that owns the string. The -//! // `c_buffer` pointer will be deallocated when `my_c_string` goes out of scope. -//! let my_c_string = my_string.to_c_str(); -//! unsafe { -//! puts(my_c_string.as_ptr()); -//! } -//! -//! // Don't save/return the pointer to the C string, the `c_buffer` will be -//! // deallocated when this block returns! -//! my_string.with_c_str(|c_buffer| { -//! unsafe { puts(c_buffer); } -//! }); -//! } -//! ``` - -use core::prelude::*; -use libc; - -use cmp::Ordering; -use fmt; -use hash; -use mem; -use ptr; -use slice::{self, IntSliceExt}; -use str; -use string::String; -use core::kinds::marker; - -/// The representation of a C String. -/// -/// This structure wraps a `*libc::c_char`, and will automatically free the -/// memory it is pointing to when it goes out of scope. -#[allow(missing_copy_implementations)] -pub struct CString { - buf: *const libc::c_char, - owns_buffer_: bool, -} - -unsafe impl Send for CString { } -unsafe impl Sync for CString { } - -impl Clone for CString { - /// Clone this CString into a new, uniquely owned CString. For safety - /// reasons, this is always a deep clone with the memory allocated - /// with C's allocator API, rather than the usual shallow clone. - fn clone(&self) -> CString { - let len = self.len() + 1; - let buf = unsafe { libc::malloc(len as libc::size_t) } as *mut libc::c_char; - if buf.is_null() { ::alloc::oom() } - unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); } - CString { buf: buf as *const libc::c_char, owns_buffer_: true } - } -} - -impl PartialEq for CString { - fn eq(&self, other: &CString) -> bool { - // Check if the two strings share the same buffer - if self.buf as uint == other.buf as uint { - true - } else { - unsafe { - libc::strcmp(self.buf, other.buf) == 0 - } - } - } -} - -impl PartialOrd for CString { - #[inline] - fn partial_cmp(&self, other: &CString) -> Option { - self.as_bytes().partial_cmp(other.as_bytes()) - } -} - -impl Eq for CString {} - -impl hash::Hash for CString { - #[inline] - fn hash(&self, state: &mut S) { - self.as_bytes().hash(state) - } -} - -impl CString { - /// Create a C String from a pointer, with memory managed by C's allocator - /// API, so avoid calling it with a pointer to memory managed by Rust's - /// allocator API, as the behaviour would not be well defined. - /// - ///# Panics - /// - /// Panics if `buf` is null - pub unsafe fn new(buf: *const libc::c_char, owns_buffer: bool) -> CString { - assert!(!buf.is_null()); - CString { buf: buf, owns_buffer_: owns_buffer } - } - - /// Return a pointer to the NUL-terminated string data. - /// - /// `.as_ptr` returns an internal pointer into the `CString`, and - /// may be invalidated when the `CString` falls out of scope (the - /// destructor will run, freeing the allocation if there is - /// one). - /// - /// ```rust - /// use std::c_str::ToCStr; - /// - /// let foo = "some string"; - /// - /// // right - /// let x = foo.to_c_str(); - /// let p = x.as_ptr(); - /// - /// // wrong (the CString will be freed, invalidating `p`) - /// let p = foo.to_c_str().as_ptr(); - /// ``` - /// - /// # Example - /// - /// ```rust - /// extern crate libc; - /// - /// use std::c_str::ToCStr; - /// - /// fn main() { - /// let c_str = "foo bar".to_c_str(); - /// unsafe { - /// libc::puts(c_str.as_ptr()); - /// } - /// } - /// ``` - pub fn as_ptr(&self) -> *const libc::c_char { - self.buf - } - - /// Return a mutable pointer to the NUL-terminated string data. - /// - /// `.as_mut_ptr` returns an internal pointer into the `CString`, and - /// may be invalidated when the `CString` falls out of scope (the - /// destructor will run, freeing the allocation if there is - /// one). - /// - /// ```rust - /// use std::c_str::ToCStr; - /// - /// let foo = "some string"; - /// - /// // right - /// let mut x = foo.to_c_str(); - /// let p = x.as_mut_ptr(); - /// - /// // wrong (the CString will be freed, invalidating `p`) - /// let p = foo.to_c_str().as_mut_ptr(); - /// ``` - pub fn as_mut_ptr(&mut self) -> *mut libc::c_char { - self.buf as *mut _ - } - - /// Returns whether or not the `CString` owns the buffer. - pub fn owns_buffer(&self) -> bool { - self.owns_buffer_ - } - - /// Converts the CString into a `&[u8]` without copying. - /// Includes the terminating NUL byte. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8] { - unsafe { - slice::from_raw_buf(&self.buf, self.len() + 1).as_unsigned() - } - } - - /// Converts the CString into a `&[u8]` without copying. - /// Does not include the terminating NUL byte. - #[inline] - pub fn as_bytes_no_nul<'a>(&'a self) -> &'a [u8] { - unsafe { - slice::from_raw_buf(&self.buf, self.len()).as_unsigned() - } - } - - /// Converts the CString into a `&str` without copying. - /// Returns None if the CString is not UTF-8. - #[inline] - pub fn as_str<'a>(&'a self) -> Option<&'a str> { - let buf = self.as_bytes_no_nul(); - str::from_utf8(buf).ok() - } - - /// Return a CString iterator. - pub fn iter<'a>(&'a self) -> CChars<'a> { - CChars { - ptr: self.buf, - marker: marker::ContravariantLifetime, - } - } - - /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper. - /// - /// Any ownership of the buffer by the `CString` wrapper is - /// forgotten, meaning that the backing allocation of this - /// `CString` is not automatically freed if it owns the - /// allocation. In this case, a user of `.unwrap()` should ensure - /// the allocation is freed, to avoid leaking memory. You should - /// use libc's memory allocator in this case. - /// - /// Prefer `.as_ptr()` when just retrieving a pointer to the - /// string data, as that does not relinquish ownership. - pub unsafe fn into_inner(mut self) -> *const libc::c_char { - self.owns_buffer_ = false; - self.buf - } - - /// Return the number of bytes in the CString (not including the NUL - /// terminator). - #[inline] - pub fn len(&self) -> uint { - unsafe { libc::strlen(self.buf) as uint } - } - - /// Returns if there are no bytes in this string - #[inline] - pub fn is_empty(&self) -> bool { self.len() == 0 } -} - -impl Drop for CString { - fn drop(&mut self) { - if self.owns_buffer_ { - unsafe { - libc::free(self.buf as *mut libc::c_void) - } - } - } -} - -impl fmt::Show for CString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - String::from_utf8_lossy(self.as_bytes_no_nul()).fmt(f) - } -} - -/// A generic trait for converting a value to a CString. -pub trait ToCStr for Sized? { - /// Copy the receiver into a CString. - /// - /// # Panics - /// - /// Panics the task if the receiver has an interior null. - fn to_c_str(&self) -> CString; - - /// Unsafe variant of `to_c_str()` that doesn't check for nulls. - unsafe fn to_c_str_unchecked(&self) -> CString; - - /// Work with a temporary CString constructed from the receiver. - /// The provided `*libc::c_char` will be freed immediately upon return. - /// - /// # Example - /// - /// ```rust - /// extern crate libc; - /// - /// use std::c_str::ToCStr; - /// - /// fn main() { - /// let s = "PATH".with_c_str(|path| unsafe { - /// libc::getenv(path) - /// }); - /// } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the receiver has an interior null. - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - let c_str = self.to_c_str(); - f(c_str.as_ptr()) - } - - /// Unsafe variant of `with_c_str()` that doesn't check for nulls. - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - let c_str = self.to_c_str_unchecked(); - f(c_str.as_ptr()) - } -} - -impl ToCStr for str { - #[inline] - fn to_c_str(&self) -> CString { - self.as_bytes().to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_bytes().to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str_unchecked(f) - } -} - -impl ToCStr for String { - #[inline] - fn to_c_str(&self) -> CString { - self.as_bytes().to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_bytes().to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str_unchecked(f) - } -} - -// The length of the stack allocated buffer for `vec.with_c_str()` -const BUF_LEN: uint = 128; - -impl ToCStr for [u8] { - fn to_c_str(&self) -> CString { - let mut cs = unsafe { self.to_c_str_unchecked() }; - check_for_null(self, cs.as_mut_ptr()); - cs - } - - unsafe fn to_c_str_unchecked(&self) -> CString { - let self_len = self.len(); - let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8; - if buf.is_null() { ::alloc::oom() } - - ptr::copy_memory(buf, self.as_ptr(), self_len); - *buf.offset(self_len as int) = 0; - - CString::new(buf as *const libc::c_char, true) - } - - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - unsafe { with_c_str(self, true, f) } - } - - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - with_c_str(self, false, f) - } -} - -impl<'a, Sized? T: ToCStr> ToCStr for &'a T { - #[inline] - fn to_c_str(&self) -> CString { - (**self).to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - (**self).to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - (**self).with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - (**self).with_c_str_unchecked(f) - } -} - -// Unsafe function that handles possibly copying the &[u8] into a stack array. -unsafe fn with_c_str(v: &[u8], checked: bool, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, -{ - let c_str = if v.len() < BUF_LEN { - let mut buf: [u8; BUF_LEN] = mem::uninitialized(); - slice::bytes::copy_memory(&mut buf, v); - buf[v.len()] = 0; - - let buf = buf.as_mut_ptr(); - if checked { - check_for_null(v, buf as *mut libc::c_char); - } - - return f(buf as *const libc::c_char) - } else if checked { - v.to_c_str() - } else { - v.to_c_str_unchecked() - }; - - f(c_str.as_ptr()) -} - -#[inline] -fn check_for_null(v: &[u8], buf: *mut libc::c_char) { - for i in range(0, v.len()) { - unsafe { - let p = buf.offset(i as int); - assert!(*p != 0); - } - } -} - -/// External iterator for a CString's bytes. -/// -/// Use with the `std::iter` module. -#[allow(raw_pointer_deriving)] -#[derive(Clone)] -pub struct CChars<'a> { - ptr: *const libc::c_char, - marker: marker::ContravariantLifetime<'a>, -} - -impl<'a> Iterator for CChars<'a> { - type Item = libc::c_char; - - fn next(&mut self) -> Option { - let ch = unsafe { *self.ptr }; - if ch == 0 { - None - } else { - self.ptr = unsafe { self.ptr.offset(1) }; - Some(ch) - } - } -} - -/// Parses a C "multistring", eg windows env values or -/// the req->ptr result in a uv_fs_readdir() call. -/// -/// Optionally, a `count` can be passed in, limiting the -/// parsing to only being done `count`-times. -/// -/// The specified closure is invoked with each string that -/// is found, and the number of strings found is returned. -pub unsafe fn from_c_multistring(buf: *const libc::c_char, - count: Option, - mut f: F) - -> uint where - F: FnMut(&CString), -{ - - let mut curr_ptr: uint = buf as uint; - let mut ctr = 0; - let (limited_count, limit) = match count { - Some(limit) => (true, limit), - None => (false, 0) - }; - while ((limited_count && ctr < limit) || !limited_count) - && *(curr_ptr as *const libc::c_char) != 0 as libc::c_char { - let cstr = CString::new(curr_ptr as *const libc::c_char, false); - f(&cstr); - curr_ptr += cstr.len() + 1; - ctr += 1; - } - return ctr; -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use super::*; - use ptr; - use thread::Thread; - use libc; - - #[test] - fn test_str_multistring_parsing() { - unsafe { - let input = b"zero\0one\0\0"; - let ptr = input.as_ptr(); - let expected = ["zero", "one"]; - let mut it = expected.iter(); - let result = from_c_multistring(ptr as *const libc::c_char, None, |c| { - let cbytes = c.as_bytes_no_nul(); - assert_eq!(cbytes, it.next().unwrap().as_bytes()); - }); - assert_eq!(result, 2); - assert!(it.next().is_none()); - } - } - - #[test] - fn test_str_to_c_str() { - let c_str = "".to_c_str(); - unsafe { - assert_eq!(*c_str.as_ptr().offset(0), 0); - } - - let c_str = "hello".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 'l' as libc::c_char); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'o' as libc::c_char); - assert_eq!(*buf.offset(5), 0); - } - } - - #[test] - fn test_vec_to_c_str() { - let b: &[u8] = &[]; - let c_str = b.to_c_str(); - unsafe { - assert_eq!(*c_str.as_ptr().offset(0), 0); - } - - let c_str = b"hello".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 'l' as libc::c_char); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'o' as libc::c_char); - assert_eq!(*buf.offset(5), 0); - } - - let c_str = b"foo\xFF".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'f' as libc::c_char); - assert_eq!(*buf.offset(1), 'o' as libc::c_char); - assert_eq!(*buf.offset(2), 'o' as libc::c_char); - assert_eq!(*buf.offset(3), 0xffu8 as libc::c_char); - assert_eq!(*buf.offset(4), 0); - } - } - - #[test] - fn test_unwrap() { - let c_str = "hello".to_c_str(); - unsafe { libc::free(c_str.into_inner() as *mut libc::c_void) } - } - - #[test] - fn test_as_ptr() { - let c_str = "hello".to_c_str(); - let len = unsafe { libc::strlen(c_str.as_ptr()) }; - assert_eq!(len, 5); - } - - #[test] - fn test_iterator() { - let c_str = "".to_c_str(); - let mut iter = c_str.iter(); - assert_eq!(iter.next(), None); - - let c_str = "hello".to_c_str(); - let mut iter = c_str.iter(); - assert_eq!(iter.next(), Some('h' as libc::c_char)); - assert_eq!(iter.next(), Some('e' as libc::c_char)); - assert_eq!(iter.next(), Some('l' as libc::c_char)); - assert_eq!(iter.next(), Some('l' as libc::c_char)); - assert_eq!(iter.next(), Some('o' as libc::c_char)); - assert_eq!(iter.next(), None); - } - - #[test] - fn test_to_c_str_fail() { - assert!(Thread::spawn(move|| { "he\x00llo".to_c_str() }).join().is_err()); - } - - #[test] - fn test_to_c_str_unchecked() { - unsafe { - let c_string = "he\x00llo".to_c_str_unchecked(); - let buf = c_string.as_ptr(); - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 0); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'l' as libc::c_char); - assert_eq!(*buf.offset(5), 'o' as libc::c_char); - assert_eq!(*buf.offset(6), 0); - } - } - - #[test] - fn test_as_bytes() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_bytes(), b"hello\0"); - let c_str = "".to_c_str(); - assert_eq!(c_str.as_bytes(), b"\0"); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_bytes(), b"foo\xFF\0"); - } - - #[test] - fn test_as_bytes_no_nul() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_bytes_no_nul(), b"hello"); - let c_str = "".to_c_str(); - let exp: &[u8] = &[]; - assert_eq!(c_str.as_bytes_no_nul(), exp); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_bytes_no_nul(), b"foo\xFF"); - } - - #[test] - fn test_as_str() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_str(), Some("hello")); - let c_str = "".to_c_str(); - assert_eq!(c_str.as_str(), Some("")); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_str(), None); - } - - #[test] - #[should_fail] - fn test_new_fail() { - let _c_str = unsafe { CString::new(ptr::null(), false) }; - } - - #[test] - fn test_clone() { - let a = "hello".to_c_str(); - let b = a.clone(); - assert!(a == b); - } - - #[test] - fn test_clone_noleak() { - fn foo(f: F) where F: FnOnce(&CString) { - let s = "test".to_string(); - let c = s.to_c_str(); - // give the closure a non-owned CString - let mut c_ = unsafe { CString::new(c.as_ptr(), false) }; - f(&c_); - // muck with the buffer for later printing - unsafe { *c_.as_mut_ptr() = 'X' as libc::c_char } - } - - let mut c_: Option = None; - foo(|c| { - c_ = Some(c.clone()); - c.clone(); - // force a copy, reading the memory - c.as_bytes().to_vec(); - }); - let c_ = c_.unwrap(); - // force a copy, reading the memory - c_.as_bytes().to_vec(); - } -} - -#[cfg(test)] -mod bench { - extern crate test; - - use prelude::v1::*; - use self::test::Bencher; - use libc; - use c_str::ToCStr; - - #[inline] - fn check(s: &str, c_str: *const libc::c_char) { - let s_buf = s.as_ptr(); - for i in range(0, s.len()) { - unsafe { - assert_eq!( - *s_buf.offset(i as int) as libc::c_char, - *c_str.offset(i as int)); - } - } - } - - static S_SHORT: &'static str = "Mary"; - static S_MEDIUM: &'static str = "Mary had a little lamb"; - static S_LONG: &'static str = "\ - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb"; - - fn bench_to_string(b: &mut Bencher, s: &str) { - b.iter(|| { - let c_str = s.to_c_str(); - check(s, c_str.as_ptr()); - }) - } - - #[bench] - fn bench_to_c_str_short(b: &mut Bencher) { - bench_to_string(b, S_SHORT) - } - - #[bench] - fn bench_to_c_str_medium(b: &mut Bencher) { - bench_to_string(b, S_MEDIUM) - } - - #[bench] - fn bench_to_c_str_long(b: &mut Bencher) { - bench_to_string(b, S_LONG) - } - - fn bench_to_c_str_unchecked(b: &mut Bencher, s: &str) { - b.iter(|| { - let c_str = unsafe { s.to_c_str_unchecked() }; - check(s, c_str.as_ptr()) - }) - } - - #[bench] - fn bench_to_c_str_unchecked_short(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_SHORT) - } - - #[bench] - fn bench_to_c_str_unchecked_medium(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_MEDIUM) - } - - #[bench] - fn bench_to_c_str_unchecked_long(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_LONG) - } - - fn bench_with_c_str(b: &mut Bencher, s: &str) { - b.iter(|| { - s.with_c_str(|c_str_buf| check(s, c_str_buf)) - }) - } - - #[bench] - fn bench_with_c_str_short(b: &mut Bencher) { - bench_with_c_str(b, S_SHORT) - } - - #[bench] - fn bench_with_c_str_medium(b: &mut Bencher) { - bench_with_c_str(b, S_MEDIUM) - } - - #[bench] - fn bench_with_c_str_long(b: &mut Bencher) { - bench_with_c_str(b, S_LONG) - } - - fn bench_with_c_str_unchecked(b: &mut Bencher, s: &str) { - b.iter(|| { - unsafe { - s.with_c_str_unchecked(|c_str_buf| check(s, c_str_buf)) - } - }) - } - - #[bench] - fn bench_with_c_str_unchecked_short(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_SHORT) - } - - #[bench] - fn bench_with_c_str_unchecked_medium(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_MEDIUM) - } - - #[bench] - fn bench_with_c_str_unchecked_long(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_LONG) - } -} diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs deleted file mode 100644 index 4a20208f31a6a..0000000000000 --- a/src/libstd/c_vec.rs +++ /dev/null @@ -1,232 +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, FnOnce}; -use option::Option; -use option::Option::{Some, None}; -use ptr::PtrExt; -use ptr; -use raw; -use slice::AsSlice; -use thunk::{Thunk}; - -/// 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) { - match self.dtor.take() { - None => (), - Some(f) => f.invoke(()) - } - } -} - -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 { - assert!(base != ptr::null_mut()); - CVec { - base: base, - len: len, - dtor: None, - } - } - - /// 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 fn 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: F) - -> CVec - where F : FnOnce(), F : Send - { - assert!(base != ptr::null_mut()); - let dtor: Thunk = Thunk::new(dtor); - CVec { - base: base, - len: len, - dtor: Some(dtor) - } - } - - /// View the stored data as a mutable slice. - pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { - unsafe { - mem::transmute(raw::Slice { data: self.base as *const T, len: self.len }) - } - } - - /// 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> { - if ofs < self.len { - Some(unsafe { &*self.base.offset(ofs as int) }) - } else { - None - } - } - - /// 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> { - if ofs < self.len { - Some(unsafe { &mut *self.base.offset(ofs as int) }) - } else { - None - } - } - - /// 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 into_inner(mut self) -> *mut T { - self.dtor = None; - self.base - } - - /// Returns the number of items in this vector. - pub fn len(&self) -> uint { self.len } - - /// Returns whether this vector is empty. - pub fn is_empty(&self) -> bool { self.len() == 0 } -} - -impl AsSlice for CVec { - /// View the stored data as a slice. - fn as_slice<'a>(&'a self) -> &'a [T] { - unsafe { - mem::transmute(raw::Slice { data: self.base as *const T, len: self.len }) - } - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - - use super::CVec; - use libc; - use ptr; - - fn malloc(n: uint) -> CVec { - unsafe { - let mem = ptr::Unique(libc::malloc(n as libc::size_t)); - if mem.0.is_null() { ::alloc::oom() } - - CVec::new_with_dtor(mem.0 as *mut u8, - n, - move|| { libc::free(mem.0 as *mut libc::c_void); }) - } - } - - #[test] - fn test_basic() { - let mut cv = malloc(16); - - *cv.get_mut(3).unwrap() = 8; - *cv.get_mut(4).unwrap() = 9; - assert_eq!(*cv.get(3).unwrap(), 8); - assert_eq!(*cv.get(4).unwrap(), 9); - assert_eq!(cv.len(), 16); - } - - #[test] - #[should_fail] - fn test_panic_at_null() { - unsafe { - CVec::new(ptr::null_mut::(), 9); - } - } - - #[test] - fn test_overrun_get() { - let cv = malloc(16); - - assert!(cv.get(17).is_none()); - } - - #[test] - fn test_overrun_set() { - let mut cv = malloc(16); - - assert!(cv.get_mut(17).is_none()); - } - - #[test] - fn test_unwrap() { - unsafe { - let cv = CVec::new_with_dtor(1 as *mut int, - 0, - move|:| panic!("Don't run this destructor!")); - let p = cv.into_inner(); - assert_eq!(p, 1 as *mut int); - } - } - -} diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index de3d75ffb3242..afe8b3ef698f8 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -17,7 +17,7 @@ use prelude::v1::*; -use c_str::ToCStr; +use ffi::CString; use mem; use os; use str; @@ -51,13 +51,11 @@ impl DynamicLibrary { /// Lazily open a dynamic library. When passed None it gives a /// handle to the calling process - pub fn open(filename: Option) - -> Result { + pub fn open(filename: Option<&Path>) -> Result { unsafe { - let mut filename = filename; let maybe_library = dl::check_for_errors_in(|| { - match filename.take() { - Some(name) => dl::open_external(name), + match filename { + Some(name) => dl::open_external(name.as_vec()), None => dl::open_internal() } }); @@ -131,9 +129,8 @@ impl DynamicLibrary { // T but that feature is still unimplemented let maybe_symbol_value = dl::check_for_errors_in(|| { - symbol.with_c_str(|raw_string| { - dl::symbol(self.handle, raw_string) - }) + let raw_string = CString::from_slice(symbol.as_bytes()); + dl::symbol(self.handle, raw_string.as_ptr()) }); // The value must not be constructed if there is an error so @@ -157,7 +154,7 @@ mod test { fn test_loading_cosine() { // The math library does not need to be loaded since it is already // statically linked in - let none: Option = None; // appease the typechecker + let none: Option<&Path> = None; // appease the typechecker let libm = match DynamicLibrary::open(none) { Err(error) => panic!("Could not load self as module: {}", error), Ok(libm) => libm @@ -202,17 +199,17 @@ mod test { target_os = "freebsd", target_os = "dragonfly"))] pub mod dl { - use self::Rtld::*; - + pub use self::Rtld::*; use prelude::v1::*; - use c_str::{CString, ToCStr}; + + use ffi::{self, CString}; + use str; use libc; use ptr; - pub unsafe fn open_external(filename: T) -> *mut u8 { - filename.with_c_str(|raw_name| { - dlopen(raw_name, Lazy as libc::c_int) as *mut u8 - }) + pub unsafe fn open_external(filename: &[u8]) -> *mut u8 { + let s = CString::from_slice(filename); + dlopen(s.as_ptr(), Lazy as libc::c_int) as *mut u8 } pub unsafe fn open_internal() -> *mut u8 { @@ -236,8 +233,8 @@ pub mod dl { let ret = if ptr::null() == last_error { Ok(result) } else { - Err(String::from_str(CString::new(last_error, false).as_str() - .unwrap())) + let s = ffi::c_str_to_bytes(&last_error); + Err(str::from_utf8(s).unwrap().to_string()) }; ret @@ -273,8 +270,8 @@ pub mod dl { #[cfg(target_os = "windows")] pub mod dl { - use c_str::ToCStr; use iter::IteratorExt; + use iter::Iterator; use libc; use ops::FnOnce; use os; @@ -287,10 +284,9 @@ pub mod dl { use string::String; use vec::Vec; - pub unsafe fn open_external(filename: T) -> *mut u8 { + pub unsafe fn open_external(filename: &[u8]) -> *mut u8 { // Windows expects Unicode data - let filename_cstr = filename.to_c_str(); - let filename_str = str::from_utf8(filename_cstr.as_bytes_no_nul()).unwrap(); + let filename_str = str::from_utf8(filename).unwrap(); let mut filename_str: Vec = filename_str.utf16_units().collect(); filename_str.push(0); LoadLibraryW(filename_str.as_ptr() as *const libc::c_void) as *mut u8 diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs new file mode 100644 index 0000000000000..bef2344d9e8bc --- /dev/null +++ b/src/libstd/ffi/c_str.rs @@ -0,0 +1,218 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use fmt; +use iter::IteratorExt; +use libc; +use mem; +use ops::Deref; +use slice::{self, SliceExt, AsSlice}; +use string::String; +use vec::Vec; + +/// A type representing a C-compatible string +/// +/// This type serves the primary purpose of being able to generate a +/// C-compatible string from a Rust byte slice or vector. An instance of this +/// type is a static guarantee that the underlying bytes contain no interior 0 +/// bytes and the final byte is 0. +/// +/// A `CString` is created from either a byte slice or a byte vector. After +/// being created, a `CString` predominately inherits all of its methods from +/// the `Deref` implementation to `[libc::c_char]`. Note that the underlying +/// array is represented as an array of `libc::c_char` as opposed to `u8`. A +/// `u8` slice can be obtained with the `as_bytes` method. Slices produced from +/// a `CString` do *not* contain the trailing nul terminator unless otherwise +/// specified. +/// +/// # Example +/// +/// ```no_run +/// # extern crate libc; +/// # fn main() { +/// use std::ffi::CString; +/// use libc; +/// +/// extern { +/// fn my_printer(s: *const libc::c_char); +/// } +/// +/// let to_print = "Hello, world!"; +/// let c_to_print = CString::from_slice(to_print.as_bytes()); +/// unsafe { +/// my_printer(c_to_print.as_ptr()); +/// } +/// # } +/// ``` +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +pub struct CString { + inner: Vec, +} + +impl CString { + /// Create a new C-compatible string from a byte slice. + /// + /// This method will copy the data of the slice provided into a new + /// allocation, ensuring that there is a trailing 0 byte. + /// + /// # Panics + /// + /// This function will panic if there are any 0 bytes already in the slice + /// provided. + pub fn from_slice(v: &[u8]) -> CString { + CString::from_vec(v.to_vec()) + } + + /// Create a C-compatible string from a byte vector. + /// + /// This method will consume ownership of the provided vector, appending a 0 + /// byte to the end after verifying that there are no interior 0 bytes. + /// + /// # Panics + /// + /// This function will panic if there are any 0 bytes already in the vector + /// provided. + pub fn from_vec(v: Vec) -> CString { + assert!(!v.iter().any(|&x| x == 0)); + unsafe { CString::from_vec_unchecked(v) } + } + + /// Create a C-compatibel string from a byte vector without checking for + /// interior 0 bytes. + /// + /// This method is equivalent to `from_vec` except that no runtime assertion + /// is made that `v` contains no 0 bytes. + pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { + v.push(0); + CString { inner: mem::transmute(v) } + } + + /// Create a view into this C string which includes the trailing nul + /// terminator at the end of the string. + pub fn as_slice_with_nul(&self) -> &[libc::c_char] { self.inner.as_slice() } + + /// Similar to the `as_slice` method, but returns a `u8` slice instead of a + /// `libc::c_char` slice. + pub fn as_bytes(&self) -> &[u8] { + unsafe { mem::transmute(self.as_slice()) } + } + + /// Equivalend to `as_slice_with_nul` except that the type returned is a + /// `u8` slice instead of a `libc::c_char` slice. + pub fn as_bytes_with_nul(&self) -> &[u8] { + unsafe { mem::transmute(self.as_slice_with_nul()) } + } +} + +impl Deref for CString { + type Target = [libc::c_char]; + + fn deref(&self) -> &[libc::c_char] { + self.inner.slice_to(self.inner.len() - 1) + } +} + +impl fmt::Show for CString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + String::from_utf8_lossy(self.as_bytes()).fmt(f) + } +} + +/// Interpret a C string as a byte slice. +/// +/// This function will calculate the length of the C string provided, and it +/// will then return a corresponding slice for the contents of the C string not +/// including the nul terminator. +/// +/// This function will tie the lifetime of the returned slice to the lifetime of +/// the pointer provided. This is done to help prevent the slice from escaping +/// the lifetime of the pointer itself. If a longer lifetime is needed, then +/// `mem::copy_lifetime` should be used. +/// +/// This function is unsafe because there is no guarantee of the validity of the +/// pointer `raw` or a guarantee that a nul terminator will be found. +/// +/// # Example +/// +/// ```no_run +/// # extern crate libc; +/// # fn main() { +/// use std::ffi; +/// use std::str; +/// use libc; +/// +/// extern { +/// fn my_string() -> *const libc::c_char; +/// } +/// +/// unsafe { +/// let to_print = my_string(); +/// let slice = ffi::c_str_to_bytes(&to_print); +/// println!("string returned: {}", str::from_utf8(slice).unwrap()); +/// } +/// # } +/// ``` +pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] { + let len = libc::strlen(*raw); + slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint) +} + +/// Interpret a C string as a byte slice with the nul terminator. +/// +/// This function is identical to `from_raw_buf` except that the returned slice +/// will include the nul terminator of the string. +pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) -> &'a [u8] { + let len = libc::strlen(*raw) + 1; + slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint) +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + use super::*; + use libc; + use mem; + + #[test] + fn c_to_rust() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const libc::c_char; + unsafe { + assert_eq!(c_str_to_bytes(&ptr), b"123"); + assert_eq!(c_str_to_bytes_with_nul(&ptr), b"123\0"); + } + } + + #[test] + fn simple() { + let s = CString::from_slice(b"1234"); + assert_eq!(s.as_bytes(), b"1234"); + assert_eq!(s.as_bytes_with_nul(), b"1234\0"); + unsafe { + assert_eq!(s.as_slice(), + mem::transmute::<_, &[libc::c_char]>(b"1234")); + assert_eq!(s.as_slice_with_nul(), + mem::transmute::<_, &[libc::c_char]>(b"1234\0")); + } + } + + #[should_fail] #[test] + fn build_with_zero1() { CString::from_slice(b"\0"); } + #[should_fail] #[test] + fn build_with_zero2() { CString::from_vec(vec![0]); } + + #[test] + fn build_with_zero3() { + unsafe { + let s = CString::from_vec_unchecked(vec![0]); + assert_eq!(s.as_bytes(), b"\0"); + } + } +} diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs new file mode 100644 index 0000000000000..cc86f804e3eb1 --- /dev/null +++ b/src/libstd/ffi/mod.rs @@ -0,0 +1,20 @@ +// Copyright 2015 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 related to FFI bindings. + +#![unstable = "module just underwent fairly large reorganization and the dust \ + still needs to settle"] + +pub use self::c_str::CString; +pub use self::c_str::c_str_to_bytes; +pub use self::c_str::c_str_to_bytes_with_nul; + +mod c_str; diff --git a/src/libstd/io/net/pipe.rs b/src/libstd/io/net/pipe.rs index daefdd28b306a..738c70412f78a 100644 --- a/src/libstd/io/net/pipe.rs +++ b/src/libstd/io/net/pipe.rs @@ -22,7 +22,8 @@ use prelude::v1::*; -use c_str::ToCStr; +use ffi::CString; +use path::BytesContainer; use io::{Listener, Acceptor, IoResult, TimedOut, standard_error}; use sys::pipe::UnixAcceptor as UnixAcceptorImp; use sys::pipe::UnixListener as UnixListenerImp; @@ -53,8 +54,9 @@ impl UnixStream { /// let mut stream = UnixStream::connect(&server); /// stream.write(&[1, 2, 3]); /// ``` - pub fn connect(path: &P) -> IoResult { - UnixStreamImp::connect(&path.to_c_str(), None) + pub fn connect(path: P) -> IoResult { + let path = CString::from_slice(path.container_as_bytes()); + UnixStreamImp::connect(&path, None) .map(|inner| UnixStream { inner: inner }) } @@ -67,13 +69,15 @@ impl UnixStream { /// 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 { + pub fn connect_timeout

(path: P, timeout: Duration) + -> IoResult + where P: BytesContainer { if timeout <= Duration::milliseconds(0) { return Err(standard_error(TimedOut)); } - UnixStreamImp::connect(&path.to_c_str(), Some(timeout.num_milliseconds() as u64)) + let path = CString::from_slice(path.container_as_bytes()); + UnixStreamImp::connect(&path, Some(timeout.num_milliseconds() as u64)) .map(|inner| UnixStream { inner: inner }) } @@ -177,8 +181,9 @@ impl UnixListener { /// } /// # } /// ``` - pub fn bind(path: &P) -> IoResult { - UnixListenerImp::bind(&path.to_c_str()) + pub fn bind(path: P) -> IoResult { + let path = CString::from_slice(path.container_as_bytes()); + UnixListenerImp::bind(&path) .map(|inner| UnixListener { inner: inner }) } } diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 5886c9cc3e287..8abae4d46af3c 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -18,8 +18,8 @@ pub use self::ProcessExit::*; use prelude::v1::*; -use c_str::{CString, ToCStr}; use collections::HashMap; +use ffi::CString; use fmt; use hash::Hash; use io::pipe::{PipeStream, PipePair}; @@ -185,10 +185,10 @@ pub struct Command { } // FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an +// we cannot usefully take BytesContainer 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 +// for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path +// instance should be removed, and arguments bound by BytesContainer should be passed by // reference. (Here: {new, arg, args, env}.) impl Command { @@ -203,9 +203,9 @@ impl Command { /// /// Builder methods are provided to change these defaults and /// otherwise configure the process. - pub fn new(program: T) -> Command { + pub fn new(program: T) -> Command { Command { - program: program.to_c_str(), + program: CString::from_slice(program.container_as_bytes()), args: Vec::new(), env: None, cwd: None, @@ -219,27 +219,29 @@ impl Command { } /// Add an argument to pass to the program. - pub fn arg<'a, T: ToCStr>(&'a mut self, arg: T) -> &'a mut Command { - self.args.push(arg.to_c_str()); + pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command { + self.args.push(CString::from_slice(arg.container_as_bytes())); self } /// Add multiple arguments to pass to the program. - pub fn args<'a, T: ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command { - self.args.extend(args.iter().map(|arg| arg.to_c_str()));; + pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command { + self.args.extend(args.iter().map(|arg| { + CString::from_slice(arg.container_as_bytes()) + })); self } // Get a mutable borrow of the environment variable map for this `Command`. - fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { + fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { match self.env { Some(ref mut map) => map, None => { // if the env is currently just inheriting from the parent's, // materialize the parent's env into a hashtable. - self.env = Some(os::env_as_bytes().into_iter() - .map(|(k, v)| (EnvKey(k.to_c_str()), - v.to_c_str())) - .collect()); + self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| { + (EnvKey(CString::from_slice(k.as_slice())), + CString::from_slice(v.as_slice())) + }).collect()); self.env.as_mut().unwrap() } } @@ -249,15 +251,20 @@ impl Command { /// /// 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 { - self.get_env_map().insert(EnvKey(key.to_c_str()), val.to_c_str()); + pub fn env<'a, T, U>(&'a mut self, key: T, val: U) + -> &'a mut Command + where T: BytesContainer, U: BytesContainer { + let key = EnvKey(CString::from_slice(key.container_as_bytes())); + let val = CString::from_slice(val.container_as_bytes()); + self.get_env_map().insert(key, val); self } /// Removes an environment variable mapping. - pub fn env_remove<'a, T: ToCStr>(&'a mut self, key: T) -> &'a mut Command { - self.get_env_map().remove(&EnvKey(key.to_c_str())); + pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command + where T: BytesContainer { + let key = EnvKey(CString::from_slice(key.container_as_bytes())); + self.get_env_map().remove(&key); self } @@ -265,16 +272,19 @@ impl Command { /// /// 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 { - self.env = Some(env.iter().map(|&(ref k, ref v)| (EnvKey(k.to_c_str()), v.to_c_str())) - .collect()); + pub fn env_set_all<'a, T, U>(&'a mut self, env: &[(T,U)]) + -> &'a mut Command + where T: BytesContainer, U: BytesContainer { + self.env = Some(env.iter().map(|&(ref k, ref v)| { + (EnvKey(CString::from_slice(k.container_as_bytes())), + CString::from_slice(v.container_as_bytes())) + }).collect()); self } /// Set the working directory for the child process. pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command { - self.cwd = Some(dir.to_c_str()); + self.cwd = Some(CString::from_slice(dir.as_vec())); self } @@ -389,9 +399,9 @@ impl fmt::Show for Command { /// non-utf8 data is lossily converted using the utf8 replacement /// character. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes_no_nul()))); + try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes()))); for arg in self.args.iter() { - try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes_no_nul()))); + try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes()))); } Ok(()) } @@ -1208,13 +1218,13 @@ mod tests { #[test] #[cfg(windows)] fn env_map_keys_ci() { - use c_str::ToCStr; + use ffi::CString; use super::EnvKey; let mut cmd = Command::new(""); cmd.env("path", "foo"); cmd.env("Path", "bar"); let env = &cmd.env.unwrap(); - let val = env.get(&EnvKey("PATH".to_c_str())); - assert!(val.unwrap() == &"bar".to_c_str()); + let val = env.get(&EnvKey(CString::from_slice(b"PATH"))); + assert!(val.unwrap() == &CString::from_slice(b"bar")); } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 608ad9882b977..2d3a4639379cf 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -208,10 +208,10 @@ pub mod num; /* Runtime and platform support */ -pub mod thread_local; -pub mod c_str; -pub mod c_vec; +pub mod thread_local; // first for macros + pub mod dynamic_lib; +pub mod ffi; pub mod fmt; pub mod io; pub mod os; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index be8f82349c222..300ceec4b45bf 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -57,12 +57,10 @@ use string::{String, ToString}; use sync::atomic::{AtomicInt, ATOMIC_INT_INIT, Ordering}; use vec::Vec; -#[cfg(unix)] use c_str::ToCStr; +#[cfg(unix)] use ffi::{self, CString}; -#[cfg(unix)] -pub use sys::ext as unix; -#[cfg(windows)] -pub use sys::ext as windows; +#[cfg(unix)] pub use sys::ext as unix; +#[cfg(windows)] pub use sys::ext as windows; /// Get the number of cores available pub fn num_cpus() -> uint { @@ -196,15 +194,14 @@ pub fn getenv(n: &str) -> Option { /// /// Panics if `n` has any interior NULs. pub fn getenv_as_bytes(n: &str) -> Option> { - use c_str::CString; - unsafe { with_env_lock(|| { - let s = n.with_c_str(|buf| libc::getenv(buf)); + let s = CString::from_slice(n.as_bytes()); + let s = libc::getenv(s.as_ptr()) as *const _; if s.is_null() { None } else { - Some(CString::new(s as *const libc::c_char, false).as_bytes_no_nul().to_vec()) + Some(ffi::c_str_to_bytes(&s).to_vec()) } }) } @@ -253,13 +250,12 @@ pub fn setenv(n: &str, v: T) { fn _setenv(n: &str, v: &[u8]) { unsafe { with_env_lock(|| { - n.with_c_str(|nbuf| { - v.with_c_str(|vbuf| { - if libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1) != 0 { - panic!(IoError::last_error()); - } - }) - }) + let k = CString::from_slice(n.as_bytes()); + let v = CString::from_slice(v); + if libc::funcs::posix01::unistd::setenv(k.as_ptr(), + v.as_ptr(), 1) != 0 { + panic!(IoError::last_error()); + } }) } } @@ -289,11 +285,10 @@ pub fn unsetenv(n: &str) { fn _unsetenv(n: &str) { unsafe { with_env_lock(|| { - n.with_c_str(|nbuf| { - if libc::funcs::posix01::unistd::unsetenv(nbuf) != 0 { - panic!(IoError::last_error()); - } - }) + let nbuf = CString::from_slice(n.as_bytes()); + if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 { + panic!(IoError::last_error()); + } }) } } @@ -618,11 +613,10 @@ pub fn get_exit_status() -> int { #[cfg(target_os = "macos")] unsafe fn load_argc_and_argv(argc: int, argv: *const *const c_char) -> Vec> { - use c_str::CString; use iter::range; range(0, argc as uint).map(|i| { - CString::new(*argv.offset(i as int), false).as_bytes_no_nul().to_vec() + ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec() }).collect() } @@ -652,7 +646,6 @@ fn real_args_as_bytes() -> Vec> { // res #[cfg(target_os = "ios")] fn real_args_as_bytes() -> Vec> { - use c_str::CString; use iter::range; use mem; diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index bf9ffbffe7d50..2f014872402cf 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -62,7 +62,7 @@ #![experimental] use core::kinds::Sized; -use c_str::CString; +use ffi::CString; use clone::Clone; use fmt; use iter::IteratorExt; @@ -892,7 +892,7 @@ impl BytesContainer for Vec { impl BytesContainer for CString { #[inline] fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - self.as_bytes_no_nul() + self.as_bytes() } } @@ -913,21 +913,3 @@ impl<'a, Sized? T: BytesContainer> BytesContainer for &'a T { fn contains_nul(v: &T) -> bool { v.container_as_bytes().iter().any(|&x| x == 0) } - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use c_str::ToCStr; - use path::{WindowsPath, PosixPath}; - - #[test] - fn test_cstring() { - let input = "/foo/bar/baz"; - let path: PosixPath = PosixPath::new(input.to_c_str()); - assert_eq!(path.as_vec(), input.as_bytes()); - - let input = r"\foo\bar\baz"; - let path: WindowsPath = WindowsPath::new(input.to_c_str()); - assert_eq!(path.as_str().unwrap(), input); - } -} diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index ae82e201cb855..013212b27058c 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -10,19 +10,16 @@ //! POSIX file path handling -use c_str::{CString, ToCStr}; use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; use hash; use io::Writer; use iter::{AdditiveIterator, Extend}; use iter::{Iterator, IteratorExt, Map}; -use option::Option; -use option::Option::{None, Some}; use kinds::Sized; -use str::{FromStr, Str}; -use str; -use slice::{Split, AsSlice, SliceConcatExt, SliceExt}; +use option::Option::{self, Some, None}; +use slice::{AsSlice, Split, SliceExt, SliceConcatExt}; +use str::{self, FromStr, StrExt}; use vec::Vec; use super::{BytesContainer, GenericPath, GenericPathUnsafe}; @@ -86,26 +83,6 @@ impl FromStr for Path { } } -// 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 { - // The Path impl guarantees no internal NUL - unsafe { self.to_c_str_unchecked() } - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_vec().to_c_str_unchecked() - } -} - impl hash::Hash for Path { #[inline] fn hash(&self, state: &mut S) { diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index aae8d6cadefb2..cdf9034741d38 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -15,16 +15,14 @@ use self::PathPrefix::*; use ascii::AsciiExt; -use c_str::{CString, ToCStr}; use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; use hash; use io::Writer; use iter::{AdditiveIterator, Extend}; use iter::{Iterator, IteratorExt, Map, repeat}; use mem; -use option::Option; -use option::Option::{Some, None}; +use option::Option::{self, Some, None}; use slice::{SliceExt, SliceConcatExt}; use str::{SplitTerminator, FromStr, StrExt}; use string::{String, ToString}; @@ -112,26 +110,6 @@ impl FromStr for Path { } } -// 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 { - // The Path impl guarantees no internal NUL - unsafe { self.to_c_str_unchecked() } - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_vec().to_c_str_unchecked() - } -} - impl hash::Hash for Path { #[cfg(not(test))] #[inline] diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs index 4734a39c83542..86abacb936501 100644 --- a/src/libstd/rt/args.rs +++ b/src/libstd/rt/args.rs @@ -46,8 +46,9 @@ pub fn clone() -> Option>> { imp::clone() } mod imp { use prelude::v1::*; + use libc; use mem; - use slice; + use ffi; use sync::{StaticMutex, MUTEX_INIT}; @@ -95,13 +96,9 @@ mod imp { } unsafe fn load_argc_and_argv(argc: int, argv: *const *const u8) -> Vec> { + let argv = argv as *const *const libc::c_char; range(0, argc as uint).map(|i| { - let arg = *argv.offset(i as int); - let mut len = 0u; - while *arg.offset(len as int) != 0 { - len += 1u; - } - slice::from_raw_buf(&arg, len).to_vec() + ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec() }).collect() } diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index 578239c9cc42e..bb0b6fe804bea 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -15,7 +15,7 @@ use prelude::v1::*; use os; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; pub use sys::backtrace::write; diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index a48a8edd82f60..71169386c186a 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -67,7 +67,7 @@ use fmt; use intrinsics; use libc::c_void; use mem; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; use sync::{Once, ONCE_INIT}; use rt::libunwind as uw; diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 883a01fa31801..bc01ce926f8bc 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -19,7 +19,7 @@ use libc::{self, uintptr_t}; use os; use slice; use str; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; /// Dynamically inquire about whether we're running under V. /// You should usually not use this unless your test definitely diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index a441e55a732b0..a31dcc9884f46 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -14,7 +14,7 @@ use io::{self, IoError, IoResult}; use prelude::v1::*; use sys::{last_error, retry}; -use c_str::CString; +use ffi::CString; use num::Int; use path::BytesContainer; use collections; diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 3f67b284f6887..4cf891ac4985e 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -12,15 +12,16 @@ use prelude::v1::*; use self::SocketStatus::*; use self::InAddr::*; -use c_str::ToCStr; +use ffi::CString; +use ffi; use io::net::addrinfo; use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult, IoError}; use libc::{self, c_char, c_int}; -use c_str::CString; use mem; use num::Int; use ptr::{self, null, null_mut}; +use str; use sys::{self, 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}; @@ -234,9 +235,9 @@ pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>, assert!(host.is_some() || servname.is_some()); - let c_host = host.map(|x| x.to_c_str()); + let c_host = host.map(|x| CString::from_slice(x.as_bytes())); let c_host = c_host.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); - let c_serv = servname.map(|x| x.to_c_str()); + let c_serv = servname.map(|x| CString::from_slice(x.as_bytes())); let c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); let hint = hint.map(|hint| { @@ -324,7 +325,8 @@ pub fn get_address_name(addr: IpAddr) -> Result { } unsafe { - Ok(CString::new(hostbuf.as_ptr(), false).as_str().unwrap().to_string()) + Ok(str::from_utf8(ffi::c_str_to_bytes(&hostbuf.as_ptr())) + .unwrap().to_string()) } } diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index 5b261ea6b9e58..ca268a8f27ff3 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -83,12 +83,13 @@ /// 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. -use c_str::CString; -use io::{IoResult, Writer}; +use prelude::v1::*; + +use ffi; +use io::IoResult; use libc; use mem; -use option::Option::{self, Some, None}; -use result::Result::{Ok, Err}; +use str; use sync::{StaticMutex, MUTEX_INIT}; use sys_common::backtrace::*; @@ -105,9 +106,7 @@ use sys_common::backtrace::*; #[cfg(all(target_os = "ios", target_arch = "arm"))] #[inline(never)] pub fn write(w: &mut Writer) -> IoResult<()> { - use iter::{IteratorExt, range}; use result; - use slice::SliceExt; extern { fn backtrace(buf: *mut *mut libc::c_void, @@ -234,19 +233,15 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { output(w, idx,addr, None) } else { output(w, idx, addr, Some(unsafe { - CString::new(info.dli_sname, false) + ffi::c_str_to_bytes(&info.dli_sname) })) } } #[cfg(not(any(target_os = "macos", target_os = "ios")))] fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { - use iter::{Iterator, IteratorExt}; use os; - use path::GenericPath; - use ptr::PtrExt; use ptr; - use slice::SliceExt; //////////////////////////////////////////////////////////////////////// // libbacktrace.h API @@ -368,15 +363,15 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { if ret == 0 || data.is_null() { output(w, idx, addr, None) } else { - output(w, idx, addr, Some(unsafe { CString::new(data, false) })) + output(w, idx, addr, Some(unsafe { ffi::c_str_to_bytes(&data) })) } } // 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<()> { + s: Option<&[u8]>) -> IoResult<()> { try!(write!(w, " {:2}: {:2$} - ", idx, addr, HEX_WIDTH)); - match s.as_ref().and_then(|c| c.as_str()) { + match s.and_then(|s| str::from_utf8(s).ok()) { Some(string) => try!(demangle(w, string)), None => try!(write!(w, "")), } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index b49ace8e2f8d8..1ad775517bba7 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -12,7 +12,7 @@ use prelude::v1::*; -use c_str::{CString, ToCStr}; +use ffi::{self, CString}; use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; use io::{IoResult, FileStat, SeekStyle}; use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; @@ -150,6 +150,10 @@ impl Drop for FileDesc { } } +fn cstr(path: &Path) -> CString { + CString::from_slice(path.as_vec()) +} + pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { let flags = match fm { Open => 0, @@ -165,7 +169,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { libc::S_IRUSR | libc::S_IWUSR), }; - let path = path.to_c_str(); + let path = cstr(path); match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) { -1 => Err(super::last_error()), fd => Ok(FileDesc::new(fd, true)), @@ -173,7 +177,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { } pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) }) } @@ -182,7 +186,6 @@ pub fn readdir(p: &Path) -> IoResult> { use libc::{opendir, readdir_r, closedir}; fn prune(root: &CString, dirs: Vec) -> Vec { - let root = unsafe { CString::new(root.as_ptr(), false) }; let root = Path::new(root); dirs.into_iter().filter(|path| { @@ -199,7 +202,7 @@ pub fn readdir(p: &Path) -> IoResult> { let mut buf = Vec::::with_capacity(size as uint); let ptr = buf.as_mut_ptr() as *mut dirent_t; - let p = p.to_c_str(); + let p = CString::from_slice(p.as_vec()); let dir_ptr = unsafe {opendir(p.as_ptr())}; if dir_ptr as uint != 0 { @@ -207,10 +210,9 @@ pub fn readdir(p: &Path) -> IoResult> { let mut entry_ptr = 0 as *mut dirent_t; while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } { if entry_ptr.is_null() { break } - let cstr = unsafe { - CString::new(rust_list_dir_val(entry_ptr), false) - }; - paths.push(Path::new(cstr)); + paths.push(unsafe { + Path::new(ffi::c_str_to_bytes(&rust_list_dir_val(entry_ptr))) + }); } assert_eq!(unsafe { closedir(dir_ptr) }, 0); Ok(prune(&p, paths)) @@ -220,39 +222,39 @@ pub fn readdir(p: &Path) -> IoResult> { } pub fn unlink(p: &Path) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::unlink(p.as_ptr()) }) } pub fn rename(old: &Path, new: &Path) -> IoResult<()> { - let old = old.to_c_str(); - let new = new.to_c_str(); + let old = cstr(old); + let new = cstr(new); mkerr_libc(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }) } pub fn chmod(p: &Path, mode: uint) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(retry(|| unsafe { libc::chmod(p.as_ptr(), mode as libc::mode_t) })) } pub fn rmdir(p: &Path) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) }) } pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(retry(|| unsafe { libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })) } pub fn readlink(p: &Path) -> IoResult { - let c_path = p.to_c_str(); + let c_path = cstr(p); let p = c_path.as_ptr(); let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) }; if len == -1 { @@ -273,14 +275,14 @@ pub fn readlink(p: &Path) -> IoResult { } pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - let src = src.to_c_str(); - let dst = dst.to_c_str(); + let src = cstr(src); + let dst = cstr(dst); mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }) } pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - let src = src.to_c_str(); - let dst = dst.to_c_str(); + let src = cstr(src); + let dst = cstr(dst); mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }) } @@ -328,7 +330,7 @@ fn mkstat(stat: &libc::stat) -> FileStat { } pub fn stat(p: &Path) -> IoResult { - let p = p.to_c_str(); + let p = cstr(p); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::stat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -337,7 +339,7 @@ pub fn stat(p: &Path) -> IoResult { } pub fn lstat(p: &Path) -> IoResult { - let p = p.to_c_str(); + let p = cstr(p); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::lstat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -346,7 +348,7 @@ pub fn lstat(p: &Path) -> IoResult { } pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); let buf = libc::utimbuf { actime: (atime / 1000) as libc::time_t, modtime: (mtime / 1000) as libc::time_t, diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index ea0d230e8b210..6a408aa60f0bf 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -15,12 +15,14 @@ #![allow(unused_unsafe)] #![allow(unused_mut)] -extern crate libc; - -use num; -use num::{Int, SignedInt}; use prelude::v1::*; + +use ffi; use io::{self, IoResult, IoError}; +use libc; +use num::{Int, SignedInt}; +use num; +use str; use sys_common::mkerr_libc; macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => ( @@ -78,11 +80,10 @@ extern "system" { } pub fn last_gai_error(s: libc::c_int) -> IoError { - use c_str::CString; let mut err = decode_error(s); err.detail = Some(unsafe { - CString::new(gai_strerror(s), false).as_str().unwrap().to_string() + str::from_utf8(ffi::c_str_to_bytes(&gai_strerror(s))).unwrap().to_string() }); err } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 181b8fdd0f8a1..175c4e2e353f9 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -12,18 +12,18 @@ use prelude::v1::*; -use c_str::ToCStr; use error::{FromError, Error}; +use ffi::{self, CString}; use fmt; use io::{IoError, IoResult}; use libc::{self, c_int, c_char, c_void}; +use os::TMPBUF_SZ; use os; use path::{BytesContainer}; use ptr; +use str; use sys::fs::FileDesc; -use os::TMPBUF_SZ; - const BUF_BYTES : uint = 2048u; /// Returns the platform-specific value of errno @@ -108,7 +108,8 @@ pub fn error_string(errno: i32) -> String { panic!("strerror_r failure"); } - String::from_raw_buf(p as *const u8) + let p = p as *const _; + str::from_utf8(ffi::c_str_to_bytes(&p)).unwrap().to_string() } } @@ -122,21 +123,17 @@ pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { } pub fn getcwd() -> IoResult { - use c_str::CString; - let mut buf = [0 as c_char; BUF_BYTES]; unsafe { if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() { Err(IoError::last_error()) } else { - Ok(Path::new(CString::new(buf.as_ptr(), false))) + Ok(Path::new(ffi::c_str_to_bytes(&buf.as_ptr()))) } } } pub unsafe fn get_env_pairs() -> Vec> { - use c_str::CString; - extern { fn rust_env_pairs() -> *const *const c_char; } @@ -147,8 +144,7 @@ pub unsafe fn get_env_pairs() -> Vec> { } let mut result = Vec::new(); while *environ != 0 as *const _ { - let env_pair = - CString::new(*environ, false).as_bytes_no_nul().to_vec(); + let env_pair = ffi::c_str_to_bytes(&*environ).to_vec(); result.push(env_pair); environ = environ.offset(1); } @@ -234,14 +230,13 @@ pub fn load_self() -> Option> { } pub fn chdir(p: &Path) -> IoResult<()> { - p.with_c_str(|buf| { - unsafe { - match libc::chdir(buf) == (0 as c_int) { - true => Ok(()), - false => Err(IoError::last_error()), - } + let p = CString::from_slice(p.as_vec()); + unsafe { + match libc::chdir(p.as_ptr()) == (0 as c_int) { + true => Ok(()), + false => Err(IoError::last_error()), } - }) + } } pub fn page_size() -> uint { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 9063fbc2ba955..158a1ce220411 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -10,8 +10,8 @@ use prelude::v1::*; +use ffi::CString; use libc; -use c_str::CString; use mem; use sync::{Arc, Mutex}; use sync::atomic::{AtomicBool, Ordering}; @@ -48,7 +48,7 @@ fn addr_to_sockaddr_un(addr: &CString, } s.sun_family = libc::AF_UNIX as libc::sa_family_t; for (slot, value) in s.sun_path.iter_mut().zip(addr.iter()) { - *slot = value; + *slot = *value; } // count the null terminator diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index b73919fe2a2cc..5bc6b0c703b1c 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -11,8 +11,8 @@ use prelude::v1::*; use self::Req::*; -use c_str::{CString, ToCStr}; use collections; +use ffi::CString; use hash::Hash; use io::process::{ProcessExit, ExitStatus, ExitSignal}; use io::{self, IoResult, IoError, EndOfFile}; @@ -101,7 +101,7 @@ impl Process { // We may use this in the child, so perform allocations before the // fork - let devnull = "/dev/null".to_c_str(); + let devnull = b"/dev/null\0"; set_cloexec(output.fd()); @@ -204,7 +204,7 @@ impl Process { } else { libc::O_RDWR }; - libc::open(devnull.as_ptr(), flags, 0) + libc::open(devnull.as_ptr() as *const _, flags, 0) } Some(obj) => { let fd = obj.as_inner().fd(); diff --git a/src/libstd/sys/unix/timer.rs b/src/libstd/sys/unix/timer.rs index 11f29232a925d..62f3242a20625 100644 --- a/src/libstd/sys/unix/timer.rs +++ b/src/libstd/sys/unix/timer.rs @@ -54,7 +54,7 @@ use libc; use mem; use os; use ptr; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; use sync::mpsc::{channel, Sender, Receiver, TryRecvError}; use sys::c; use sys::fs::FileDesc; diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 319a458087b9b..e3b7413e37d37 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -21,7 +21,8 @@ /// 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. -use c_str::CString; +use dynamic_lib::DynamicLibrary; +use ffi; use intrinsics; use io::{IoResult, Writer}; use libc; @@ -30,10 +31,9 @@ use ops::Drop; use option::Option::{Some, None}; use path::Path; use result::Result::{Ok, Err}; -use sync::{StaticMutex, MUTEX_INIT}; use slice::SliceExt; -use str::StrExt; -use dynamic_lib::DynamicLibrary; +use str::{self, StrExt}; +use sync::{StaticMutex, MUTEX_INIT}; use sys_common::backtrace::*; @@ -357,9 +357,9 @@ pub fn write(w: &mut Writer) -> IoResult<()> { if ret == libc::TRUE { try!(write!(w, " - ")); - let cstr = unsafe { CString::new(info.Name.as_ptr(), false) }; - let bytes = cstr.as_bytes(); - match cstr.as_str() { + let ptr = info.Name.as_ptr() as *const libc::c_char; + let bytes = unsafe { ffi::c_str_to_bytes(&ptr) }; + match str::from_utf8(bytes) { Some(s) => try!(demangle(w, s)), None => try!(w.write(bytes[..bytes.len()-1])), } diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 1ee57434fb91a..945c2e8e7d156 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -133,7 +133,7 @@ pub mod compat { use intrinsics::{atomic_store_relaxed, transmute}; use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; use prelude::v1::*; - use c_str::ToCStr; + use ffi::CString; extern "system" { fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; @@ -147,14 +147,13 @@ pub mod compat { 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 - }) + let symbol = CString::from_slice(symbol.as_bytes()); + let handle = GetModuleHandleW(module.as_ptr()); + let func: uint = transmute(GetProcAddress(handle, symbol.as_ptr())); + atomic_store_relaxed(ptr, if func == 0 { + fallback + } else { + func }) } diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 9057515cad294..dcafb77e876fd 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -87,7 +87,7 @@ use prelude::v1::*; use libc; -use c_str::CString; +use ffi::CString; use mem; use ptr; use sync::{Arc, Mutex}; diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 81e8f974a1223..fc1fb7cacc650 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -12,7 +12,7 @@ use prelude::v1::*; use libc::{pid_t, c_void, c_int}; use libc; -use c_str::{CString, ToCStr}; +use ffi::CString; use io; use mem; use os; diff --git a/src/test/auxiliary/linkage-visibility.rs b/src/test/auxiliary/linkage-visibility.rs index 0b4bea49fa249..6cd94ee5602aa 100644 --- a/src/test/auxiliary/linkage-visibility.rs +++ b/src/test/auxiliary/linkage-visibility.rs @@ -27,7 +27,7 @@ fn bar() { } fn baz() { } pub fn test() { - let none: Option = None; // appease the typechecker + let none: Option<&Path> = None; // appease the typechecker let lib = DynamicLibrary::open(none).unwrap(); unsafe { assert!(lib.symbol::("foo").is_ok()); diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs index c95cf0bfdee45..22c322b86c979 100644 --- a/src/test/run-pass/c-stack-returning-int64.rs +++ b/src/test/run-pass/c-stack-returning-int64.rs @@ -12,7 +12,7 @@ extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; mod mlibc { use libc::{c_char, c_long, c_longlong}; @@ -24,11 +24,13 @@ mod mlibc { } fn atol(s: String) -> int { - s.as_slice().with_c_str(|x| unsafe { mlibc::atol(x) as int }) + let c = CString::from_slice(s.as_bytes()); + unsafe { mlibc::atol(c.as_ptr()) as int } } fn atoll(s: String) -> i64 { - s.as_slice().with_c_str(|x| unsafe { mlibc::atoll(x) as i64 }) + let c = CString::from_slice(s.as_bytes()); + unsafe { mlibc::atoll(c.as_ptr()) as i64 } } pub fn main() { diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs index 5e028d3774fc5..1a84236793b4f 100644 --- a/src/test/run-pass/const-str-ptr.rs +++ b/src/test/run-pass/const-str-ptr.rs @@ -9,7 +9,6 @@ // except according to those terms. use std::{str, string}; -use std::c_str::ToCStr; const A: [u8; 2] = ['h' as u8, 'i' as u8]; const B: &'static [u8; 2] = &A; @@ -23,8 +22,5 @@ pub fn main() { assert_eq!(String::from_raw_buf_len(C, B.len()), "hi".to_string()); assert!(*C == A[0]); assert!(*(&B[0] as *const u8) == A[0]); - - let bar = str::from_utf8_unchecked(&A).to_c_str(); - assert_eq!(bar.as_str(), "hi".to_c_str().as_str()); } } diff --git a/src/test/run-pass/foreign-fn-linkname.rs b/src/test/run-pass/foreign-fn-linkname.rs index 8a75fdd685dd1..dff1a1eaa0473 100644 --- a/src/test/run-pass/foreign-fn-linkname.rs +++ b/src/test/run-pass/foreign-fn-linkname.rs @@ -11,7 +11,7 @@ // ignore-fast doesn't like extern crate extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; mod mlibc { use libc::{c_char, size_t}; @@ -24,11 +24,10 @@ mod mlibc { fn strlen(str: String) -> uint { // C string is terminated with a zero - str.as_slice().with_c_str(|buf| { - unsafe { - mlibc::my_strlen(buf) as uint - } - }) + let s = CString::from_slice(str.as_bytes()); + unsafe { + mlibc::my_strlen(s.as_ptr()) as uint + } } pub fn main() { diff --git a/src/test/run-pass/rename-directory.rs b/src/test/run-pass/rename-directory.rs index c7aa405b513e4..d610bf09edb95 100644 --- a/src/test/run-pass/rename-directory.rs +++ b/src/test/run-pass/rename-directory.rs @@ -13,8 +13,8 @@ extern crate libc; +use std::ffi::CString; use std::io::TempDir; -use std::c_str::ToCStr; use std::io::fs::PathExtensions; use std::io::fs; use std::io; @@ -31,20 +31,17 @@ fn rename_directory() { let test_file = &old_path.join("temp.txt"); /* Write the temp input file */ - let ostream = test_file.with_c_str(|fromp| { - "w+b".with_c_str(|modebuf| { - libc::fopen(fromp, modebuf) - }) - }); + let fromp = CString::from_slice(test_file.as_vec()); + let modebuf = CString::from_slice(b"w+b"); + let ostream = libc::fopen(fromp.as_ptr(), modebuf.as_ptr()); assert!((ostream as uint != 0u)); let s = "hello".to_string(); - "hello".with_c_str(|buf| { - let write_len = libc::fwrite(buf as *const libc::c_void, - 1u as libc::size_t, - (s.len() + 1u) as libc::size_t, - ostream); - assert_eq!(write_len, (s.len() + 1) as libc::size_t) - }); + let buf = CString::from_slice(b"hello"); + let write_len = libc::fwrite(buf.as_ptr() as *mut _, + 1u as libc::size_t, + (s.len() + 1u) as libc::size_t, + ostream); + assert_eq!(write_len, (s.len() + 1) as libc::size_t); assert_eq!(libc::fclose(ostream), (0u as libc::c_int)); let new_path = tmpdir.join_many(&["quux", "blat"]); diff --git a/src/test/run-pass/variadic-ffi.rs b/src/test/run-pass/variadic-ffi.rs index ec320c1f8a309..de9d7880411a1 100644 --- a/src/test/run-pass/variadic-ffi.rs +++ b/src/test/run-pass/variadic-ffi.rs @@ -10,7 +10,7 @@ extern crate libc; -use std::c_str::{CString, ToCStr}; +use std::ffi::{self, CString}; use libc::{c_char, c_int}; // ignore-fast doesn't like extern crate @@ -22,40 +22,35 @@ extern { unsafe fn check(expected: &str, f: |*mut c_char| -> T) { let mut x = [0 as c_char; 50]; f(&mut x[0] as *mut c_char); - let res = CString::new(&x[0], false); - assert_eq!(expected, res.as_str().unwrap()); + assert_eq!(expected.as_bytes(), ffi::c_str_to_bytes(&x.as_ptr())); } pub fn main() { unsafe { // Call with just the named parameter - "Hello World\n".with_c_str(|c| { - check("Hello World\n", |s| sprintf(s, c)); - }); + let c = CString::from_slice(b"Hello World\n"); + check("Hello World\n", |s| sprintf(s, c.as_ptr())); // Call with variable number of arguments - "%d %f %c %s\n".with_c_str(|c| { - check("42 42.500000 a %d %f %c %s\n\n", |s| { - sprintf(s, c, 42i, 42.5f64, 'a' as c_int, c); - }) + let c = CString::from_slice(b"%d %f %c %s\n"); + check("42 42.500000 a %d %f %c %s\n\n", |s| { + sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr()); }); // Make a function pointer - let x: unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int = sprintf; + let x: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int = sprintf; // A function that takes a function pointer - unsafe fn call(p: unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int) { - // Call with just the named parameter via fn pointer - "Hello World\n".with_c_str(|c| { - check("Hello World\n", |s| p(s, c)); - }); + unsafe fn call(p: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int) { + // Call with just the named parameter + let c = CString::from_slice(b"Hello World\n"); + check("Hello World\n", |s| sprintf(s, c.as_ptr())); // Call with variable number of arguments - "%d %f %c %s\n".with_c_str(|c| { - check("42 42.500000 a %d %f %c %s\n\n", |s| { - p(s, c, 42i, 42.5f64, 'a' as c_int, c); - }) + let c = CString::from_slice(b"%d %f %c %s\n"); + check("42 42.500000 a %d %f %c %s\n\n", |s| { + sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr()); }); } From 0cb7a4062a3c69bb0c54f0c9136889a1006e4f62 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 3 Jan 2015 22:24:50 -0800 Subject: [PATCH 28/29] serialize: Use assoc types + less old_orphan_check This commit moves the libserialize crate (and will force the hand of the rustc-serialize crate) to not require the `old_orphan_check` feature gate as well as using associated types wherever possible. Concretely, the following changes were made: * The error type of `Encoder` and `Decoder` is now an associated type, meaning that these traits have no type parameters. * The `Encoder` and `Decoder` type parameters on the `Encodable` and `Decodable` traits have moved to the corresponding method of the trait. This movement alleviates the dependency on `old_orphan_check` but implies that implementations can no longer be specialized for the type of encoder/decoder being implemented. Due to the trait definitions changing, this is a: [breaking-change] --- src/librbml/lib.rs | 465 +- src/librustc/middle/astencode.rs | 23 + src/libserialize/collection_impls.rs | 128 +- src/libserialize/collection_impls_stage0.rs | 289 ++ src/libserialize/json.rs | 33 +- src/libserialize/json_stage0.rs | 3883 +++++++++++++++++ src/libserialize/lib.rs | 14 + src/libserialize/serialize.rs | 513 +-- src/libserialize/serialize_stage0.rs | 629 +++ src/libsyntax/ast.rs | 40 +- src/libsyntax/codemap.rs | 17 + src/libsyntax/ext/deriving/decodable.rs | 30 +- src/libsyntax/ext/deriving/encodable.rs | 32 +- src/libsyntax/owned_slice.rs | 19 + src/libsyntax/parse/token.rs | 17 + src/libsyntax/ptr.rs | 16 + .../compile-fail/variance-trait-matching-2.rs | 30 - src/test/run-pass/issue-11881.rs | 10 +- src/test/run-pass/issue-15924.rs | 2 +- src/test/run-pass/issue-4016.rs | 2 +- 20 files changed, 5755 insertions(+), 437 deletions(-) create mode 100644 src/libserialize/collection_impls_stage0.rs create mode 100644 src/libserialize/json_stage0.rs create mode 100644 src/libserialize/serialize_stage0.rs delete mode 100644 src/test/compile-fail/variance-trait-matching-2.rs diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index f7d5bfcd117d6..3acedac111d60 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -25,7 +25,7 @@ html_playground_url = "http://play.rust-lang.org/")] #![allow(unknown_features)] #![feature(macro_rules, phase, slicing_syntax, globs)] -#![feature(unboxed_closures)] +#![feature(unboxed_closures, associated_types)] #![allow(missing_docs)] extern crate serialize; @@ -417,6 +417,7 @@ pub mod reader { } } + #[cfg(stage0)] impl<'doc> serialize::Decoder for Decoder<'doc> { fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) } @@ -671,6 +672,263 @@ pub mod reader { ApplicationError(err.to_string()) } } + + #[cfg(not(stage0))] + impl<'doc> serialize::Decoder for Decoder<'doc> { + type Error = Error; + fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) } + + fn read_u64(&mut self) -> DecodeResult { Ok(doc_as_u64(try!(self.next_doc(EsU64)))) } + fn read_u32(&mut self) -> DecodeResult { Ok(doc_as_u32(try!(self.next_doc(EsU32)))) } + fn read_u16(&mut self) -> DecodeResult { Ok(doc_as_u16(try!(self.next_doc(EsU16)))) } + fn read_u8 (&mut self) -> DecodeResult { Ok(doc_as_u8 (try!(self.next_doc(EsU8 )))) } + fn read_uint(&mut self) -> DecodeResult { + let v = doc_as_u64(try!(self.next_doc(EsUint))); + if v > (::std::uint::MAX as u64) { + Err(IntTooBig(v as uint)) + } else { + Ok(v as uint) + } + } + + fn read_i64(&mut self) -> DecodeResult { + Ok(doc_as_u64(try!(self.next_doc(EsI64))) as i64) + } + fn read_i32(&mut self) -> DecodeResult { + Ok(doc_as_u32(try!(self.next_doc(EsI32))) as i32) + } + fn read_i16(&mut self) -> DecodeResult { + Ok(doc_as_u16(try!(self.next_doc(EsI16))) as i16) + } + fn read_i8 (&mut self) -> DecodeResult { + Ok(doc_as_u8(try!(self.next_doc(EsI8 ))) as i8) + } + fn read_int(&mut self) -> DecodeResult { + let v = doc_as_u64(try!(self.next_doc(EsInt))) as i64; + if v > (int::MAX as i64) || v < (int::MIN as i64) { + debug!("FIXME \\#6122: Removing this makes this function miscompile"); + Err(IntTooBig(v as uint)) + } else { + Ok(v as int) + } + } + + fn read_bool(&mut self) -> DecodeResult { + Ok(doc_as_u8(try!(self.next_doc(EsBool))) != 0) + } + + fn read_f64(&mut self) -> DecodeResult { + let bits = doc_as_u64(try!(self.next_doc(EsF64))); + Ok(unsafe { transmute(bits) }) + } + fn read_f32(&mut self) -> DecodeResult { + let bits = doc_as_u32(try!(self.next_doc(EsF32))); + Ok(unsafe { transmute(bits) }) + } + fn read_char(&mut self) -> DecodeResult { + Ok(char::from_u32(doc_as_u32(try!(self.next_doc(EsChar)))).unwrap()) + } + fn read_str(&mut self) -> DecodeResult { + Ok(try!(self.next_doc(EsStr)).as_str()) + } + + // Compound types: + fn read_enum(&mut self, name: &str, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_enum({})", name); + try!(self._check_label(name)); + + let doc = try!(self.next_doc(EsEnum)); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = try!(f(self)); + + self.parent = old_parent; + self.pos = old_pos; + Ok(result) + } + + fn read_enum_variant(&mut self, _: &[&str], + mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_enum_variant()"); + let idx = try!(self._next_uint(EsEnumVid)); + debug!(" idx={}", idx); + + let doc = try!(self.next_doc(EsEnumBody)); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = try!(f(self, idx)); + + self.parent = old_parent; + self.pos = old_pos; + Ok(result) + } + + fn read_enum_variant_arg(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_enum_variant_arg(idx={})", idx); + f(self) + } + + fn read_enum_struct_variant(&mut self, _: &[&str], + mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_enum_struct_variant()"); + let idx = try!(self._next_uint(EsEnumVid)); + debug!(" idx={}", idx); + + let doc = try!(self.next_doc(EsEnumBody)); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = try!(f(self, idx)); + + self.parent = old_parent; + self.pos = old_pos; + Ok(result) + } + + fn read_enum_struct_variant_field(&mut self, + name: &str, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx); + f(self) + } + + fn read_struct(&mut self, name: &str, _: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_struct(name={})", name); + f(self) + } + + fn read_struct_field(&mut self, name: &str, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_struct_field(name={}, idx={})", name, idx); + try!(self._check_label(name)); + f(self) + } + + fn read_tuple(&mut self, tuple_len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple()"); + self.read_seq(move |d, len| { + if len == tuple_len { + f(d) + } else { + Err(Expected(format!("Expected tuple of length `{}`, \ + found tuple of length `{}`", tuple_len, len))) + } + }) + } + + fn read_tuple_arg(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple_arg(idx={})", idx); + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&mut self, name: &str, len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple_struct(name={})", name); + self.read_tuple(len, f) + } + + fn read_tuple_struct_arg(&mut self, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple_struct_arg(idx={})", idx); + self.read_tuple_arg(idx, f) + } + + fn read_option(&mut self, mut f: F) -> DecodeResult where + F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult, + { + debug!("read_option()"); + self.read_enum("Option", move |this| { + this.read_enum_variant(&["None", "Some"], move |this, idx| { + match idx { + 0 => f(this, false), + 1 => f(this, true), + _ => { + Err(Expected(format!("Expected None or Some"))) + } + } + }) + }) + } + + fn read_seq(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_seq()"); + self.push_doc(EsVec, move |d| { + let len = try!(d._next_uint(EsVecLen)); + debug!(" len={}", len); + f(d, len) + }) + } + + fn read_seq_elt(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_seq_elt(idx={})", idx); + self.push_doc(EsVecElt, f) + } + + fn read_map(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_map()"); + self.push_doc(EsMap, move |d| { + let len = try!(d._next_uint(EsMapLen)); + debug!(" len={}", len); + f(d, len) + }) + } + + fn read_map_elt_key(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_map_elt_key(idx={})", idx); + self.push_doc(EsMapKey, f) + } + + fn read_map_elt_val(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_map_elt_val(idx={})", idx); + self.push_doc(EsMapVal, f) + } + + fn error(&mut self, err: &str) -> Error { + ApplicationError(err.to_string()) + } + } } pub mod writer { @@ -872,7 +1130,212 @@ pub mod writer { } } + #[cfg(stage0)] impl<'a, W: Writer + Seek> serialize::Encoder for Encoder<'a, W> { + + fn emit_nil(&mut self) -> EncodeResult { + Ok(()) + } + + fn emit_uint(&mut self, v: uint) -> EncodeResult { + self.wr_tagged_u64(EsUint as uint, v as u64) + } + fn emit_u64(&mut self, v: u64) -> EncodeResult { + self.wr_tagged_u64(EsU64 as uint, v) + } + fn emit_u32(&mut self, v: u32) -> EncodeResult { + self.wr_tagged_u32(EsU32 as uint, v) + } + fn emit_u16(&mut self, v: u16) -> EncodeResult { + self.wr_tagged_u16(EsU16 as uint, v) + } + fn emit_u8(&mut self, v: u8) -> EncodeResult { + self.wr_tagged_u8(EsU8 as uint, v) + } + + fn emit_int(&mut self, v: int) -> EncodeResult { + self.wr_tagged_i64(EsInt as uint, v as i64) + } + fn emit_i64(&mut self, v: i64) -> EncodeResult { + self.wr_tagged_i64(EsI64 as uint, v) + } + fn emit_i32(&mut self, v: i32) -> EncodeResult { + self.wr_tagged_i32(EsI32 as uint, v) + } + fn emit_i16(&mut self, v: i16) -> EncodeResult { + self.wr_tagged_i16(EsI16 as uint, v) + } + fn emit_i8(&mut self, v: i8) -> EncodeResult { + self.wr_tagged_i8(EsI8 as uint, v) + } + + fn emit_bool(&mut self, v: bool) -> EncodeResult { + self.wr_tagged_u8(EsBool as uint, v as u8) + } + + fn emit_f64(&mut self, v: f64) -> EncodeResult { + let bits = unsafe { mem::transmute(v) }; + self.wr_tagged_u64(EsF64 as uint, bits) + } + fn emit_f32(&mut self, v: f32) -> EncodeResult { + let bits = unsafe { mem::transmute(v) }; + self.wr_tagged_u32(EsF32 as uint, bits) + } + fn emit_char(&mut self, v: char) -> EncodeResult { + self.wr_tagged_u32(EsChar as uint, v as u32) + } + + fn emit_str(&mut self, v: &str) -> EncodeResult { + self.wr_tagged_str(EsStr as uint, v) + } + + fn emit_enum(&mut self, name: &str, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self._emit_label(name)); + try!(self.start_tag(EsEnum as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_enum_variant(&mut self, + _: &str, + v_id: uint, + _: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self._emit_tagged_uint(EsEnumVid, v_id)); + try!(self.start_tag(EsEnumBody as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_enum_variant_arg(&mut self, _: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + f(self) + } + + fn emit_enum_struct_variant(&mut self, + v_name: &str, + v_id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_enum_variant(v_name, v_id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&mut self, _: &str, _len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + f(self) + } + + fn emit_struct_field(&mut self, name: &str, _: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self._emit_label(name)); + f(self) + } + + fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_enum("Option", f) + } + fn emit_option_none(&mut self) -> EncodeResult { + self.emit_enum_variant("None", 0, 0, |_| Ok(())) + } + fn emit_option_some(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + self.emit_enum_variant("Some", 1, 1, f) + } + + fn emit_seq(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsVec as uint)); + try!(self._emit_tagged_uint(EsVecLen, len)); + try!(f(self)); + self.end_tag() + } + + fn emit_seq_elt(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsVecElt as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_map(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsMap as uint)); + try!(self._emit_tagged_uint(EsMapLen, len)); + try!(f(self)); + self.end_tag() + } + + fn emit_map_elt_key(&mut self, _idx: uint, mut f: F) -> EncodeResult where + F: FnMut(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsMapKey as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self.start_tag(EsMapVal as uint)); + try!(f(self)); + self.end_tag() + } + } + #[cfg(not(stage0))] + impl<'a, W: Writer + Seek> serialize::Encoder for Encoder<'a, W> { + type Error = io::IoError; + fn emit_nil(&mut self) -> EncodeResult { Ok(()) } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index e4d407d66a2ee..269b09a5f2ed8 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -263,18 +263,27 @@ trait def_id_encoder_helpers { fn emit_def_id(&mut self, did: ast::DefId); } +#[cfg(stage0)] impl, E> def_id_encoder_helpers for S { fn emit_def_id(&mut self, did: ast::DefId) { did.encode(self).ok().unwrap() } } +#[cfg(not(stage0))] +impl def_id_encoder_helpers for S { + fn emit_def_id(&mut self, did: ast::DefId) { + did.encode(self).ok().unwrap() + } +} + trait def_id_decoder_helpers { fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId; fn read_def_id_nodcx(&mut self, cdata: &cstore::crate_metadata) -> ast::DefId; } +#[cfg(stage0)] impl, E> def_id_decoder_helpers for D { fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId { let did: ast::DefId = Decodable::decode(self).ok().unwrap(); @@ -288,6 +297,20 @@ impl, E> def_id_decoder_helpers for D { } } +#[cfg(not(stage0))] +impl def_id_decoder_helpers for D { + fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId { + let did: ast::DefId = Decodable::decode(self).ok().unwrap(); + did.tr(dcx) + } + + fn read_def_id_nodcx(&mut self, + cdata: &cstore::crate_metadata) -> ast::DefId { + let did: ast::DefId = Decodable::decode(self).ok().unwrap(); + decoder::translate_def_id(cdata, did) + } +} + // ______________________________________________________________________ // Encoding and decoding the AST itself // diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index f2d79b1334699..7ba329c518e91 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -19,11 +19,9 @@ use std::collections::{DList, RingBuf, BTreeMap, BTreeSet, HashMap, HashSet, Vec use collections::enum_set::{EnumSet, CLike}; impl< - E, - S: Encoder, - T: Encodable -> Encodable for DList { - fn encode(&self, s: &mut S) -> Result<(), E> { + T: Encodable +> Encodable for DList { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))); @@ -33,8 +31,8 @@ impl< } } -impl,T:Decodable> Decodable for DList { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for DList { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut list = DList::new(); for i in range(0u, len) { @@ -45,12 +43,8 @@ impl,T:Decodable> Decodable for DList { } } -impl< - E, - S: Encoder, - T: Encodable -> Encodable for RingBuf { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for RingBuf { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))); @@ -60,8 +54,8 @@ impl< } } -impl,T:Decodable> Decodable for RingBuf { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for RingBuf { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut deque: RingBuf = RingBuf::new(); for i in range(0u, len) { @@ -73,12 +67,10 @@ impl,T:Decodable> Decodable for RingBuf { } impl< - E, - S: Encoder, - K: Encodable + PartialEq + Ord, - V: Encodable + PartialEq -> Encodable for BTreeMap { - fn encode(&self, e: &mut S) -> Result<(), E> { + K: Encodable + PartialEq + Ord, + V: Encodable + PartialEq +> Encodable for BTreeMap { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { let mut i = 0; for (key, val) in self.iter() { @@ -92,12 +84,10 @@ impl< } impl< - E, - D: Decoder, - K: Decodable + PartialEq + Ord, - V: Decodable + PartialEq -> Decodable for BTreeMap { - fn decode(d: &mut D) -> Result, E> { + K: Decodable + PartialEq + Ord, + V: Decodable + PartialEq +> Decodable for BTreeMap { + fn decode(d: &mut D) -> Result, D::Error> { d.read_map(|d, len| { let mut map = BTreeMap::new(); for i in range(0u, len) { @@ -111,11 +101,9 @@ impl< } impl< - E, - S: Encoder, - T: Encodable + PartialEq + Ord -> Encodable for BTreeSet { - fn encode(&self, s: &mut S) -> Result<(), E> { + T: Encodable + PartialEq + Ord +> Encodable for BTreeSet { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { let mut i = 0; for e in self.iter() { @@ -128,11 +116,9 @@ impl< } impl< - E, - D: Decoder, - T: Decodable + PartialEq + Ord -> Decodable for BTreeSet { - fn decode(d: &mut D) -> Result, E> { + T: Decodable + PartialEq + Ord +> Decodable for BTreeSet { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut set = BTreeSet::new(); for i in range(0u, len) { @@ -144,11 +130,9 @@ impl< } impl< - E, - S: Encoder, - T: Encodable + CLike -> Encodable for EnumSet { - fn encode(&self, s: &mut S) -> Result<(), E> { + T: Encodable + CLike +> Encodable for EnumSet { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { let mut bits = 0; for item in self.iter() { bits |= item.to_uint(); @@ -158,11 +142,9 @@ impl< } impl< - E, - D: Decoder, - T: Decodable + CLike -> Decodable for EnumSet { - fn decode(d: &mut D) -> Result, E> { + T: Decodable + CLike +> Decodable for EnumSet { + fn decode(d: &mut D) -> Result, D::Error> { let bits = try!(d.read_uint()); let mut set = EnumSet::new(); for bit in range(0, uint::BITS) { @@ -175,14 +157,12 @@ impl< } impl< - E, - S: Encoder, - K: Encodable + Hash + Eq, - V: Encodable, + K: Encodable + Hash + Eq, + V: Encodable, X, H: Hasher -> Encodable for HashMap { - fn encode(&self, e: &mut S) -> Result<(), E> { +> Encodable for HashMap { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { let mut i = 0; for (key, val) in self.iter() { @@ -196,14 +176,12 @@ impl< } impl< - E, - D: Decoder, - K: Decodable + Hash + Eq, - V: Decodable, + K: Decodable + Hash + Eq, + V: Decodable, S, H: Hasher + Default -> Decodable for HashMap { - fn decode(d: &mut D) -> Result, E> { +> Decodable for HashMap { + fn decode(d: &mut D) -> Result, D::Error> { d.read_map(|d, len| { let hasher = Default::default(); let mut map = HashMap::with_capacity_and_hasher(len, hasher); @@ -218,13 +196,11 @@ impl< } impl< - E, - S: Encoder, - T: Encodable + Hash + Eq, + T: Encodable + Hash + Eq, X, H: Hasher -> Encodable for HashSet { - fn encode(&self, s: &mut S) -> Result<(), E> { +> Encodable for HashSet { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { let mut i = 0; for e in self.iter() { @@ -237,13 +213,11 @@ impl< } impl< - E, - D: Decoder, - T: Decodable + Hash + Eq, + T: Decodable + Hash + Eq, S, H: Hasher + Default -> Decodable for HashSet { - fn decode(d: &mut D) -> Result, E> { +> Decodable for HashSet { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut set = HashSet::with_capacity_and_hasher(len, Default::default()); for i in range(0u, len) { @@ -254,12 +228,8 @@ impl< } } -impl< - E, - S: Encoder, - V: Encodable -> Encodable for VecMap { - fn encode(&self, e: &mut S) -> Result<(), E> { +impl Encodable for VecMap { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { for (i, (key, val)) in self.iter().enumerate() { try!(e.emit_map_elt_key(i, |e| key.encode(e))); @@ -270,12 +240,8 @@ impl< } } -impl< - E, - D: Decoder, - V: Decodable -> Decodable for VecMap { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for VecMap { + fn decode(d: &mut D) -> Result, D::Error> { d.read_map(|d, len| { let mut map = VecMap::new(); for i in range(0u, len) { diff --git a/src/libserialize/collection_impls_stage0.rs b/src/libserialize/collection_impls_stage0.rs new file mode 100644 index 0000000000000..f2d79b1334699 --- /dev/null +++ b/src/libserialize/collection_impls_stage0.rs @@ -0,0 +1,289 @@ +// 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. + +//! Implementations of serialization for structures found in libcollections + +use std::uint; +use std::default::Default; +use std::hash::{Hash, Hasher}; + +use {Decodable, Encodable, Decoder, Encoder}; +use std::collections::{DList, RingBuf, BTreeMap, BTreeSet, HashMap, HashSet, VecMap}; +use collections::enum_set::{EnumSet, CLike}; + +impl< + E, + S: Encoder, + T: Encodable +> Encodable for DList { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + } + Ok(()) + }) + } +} + +impl,T:Decodable> Decodable for DList { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut list = DList::new(); + for i in range(0u, len) { + list.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(list) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable +> Encodable for RingBuf { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + } + Ok(()) + }) + } +} + +impl,T:Decodable> Decodable for RingBuf { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut deque: RingBuf = RingBuf::new(); + for i in range(0u, len) { + deque.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(deque) + }) + } +} + +impl< + E, + S: Encoder, + K: Encodable + PartialEq + Ord, + V: Encodable + PartialEq +> Encodable for BTreeMap { + fn encode(&self, e: &mut S) -> Result<(), E> { + e.emit_map(self.len(), |e| { + let mut i = 0; + for (key, val) in self.iter() { + try!(e.emit_map_elt_key(i, |e| key.encode(e))); + try!(e.emit_map_elt_val(i, |e| val.encode(e))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + K: Decodable + PartialEq + Ord, + V: Decodable + PartialEq +> Decodable for BTreeMap { + fn decode(d: &mut D) -> Result, E> { + d.read_map(|d, len| { + let mut map = BTreeMap::new(); + for i in range(0u, len) { + let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d))); + let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d))); + map.insert(key, val); + } + Ok(map) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable + PartialEq + Ord +> Encodable for BTreeSet { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + let mut i = 0; + for e in self.iter() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + T: Decodable + PartialEq + Ord +> Decodable for BTreeSet { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut set = BTreeSet::new(); + for i in range(0u, len) { + set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(set) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable + CLike +> Encodable for EnumSet { + fn encode(&self, s: &mut S) -> Result<(), E> { + let mut bits = 0; + for item in self.iter() { + bits |= item.to_uint(); + } + s.emit_uint(bits) + } +} + +impl< + E, + D: Decoder, + T: Decodable + CLike +> Decodable for EnumSet { + fn decode(d: &mut D) -> Result, E> { + let bits = try!(d.read_uint()); + let mut set = EnumSet::new(); + for bit in range(0, uint::BITS) { + if bits & (1 << bit) != 0 { + set.insert(CLike::from_uint(1 << bit)); + } + } + Ok(set) + } +} + +impl< + E, + S: Encoder, + K: Encodable + Hash + Eq, + V: Encodable, + X, + H: Hasher +> Encodable for HashMap { + fn encode(&self, e: &mut S) -> Result<(), E> { + e.emit_map(self.len(), |e| { + let mut i = 0; + for (key, val) in self.iter() { + try!(e.emit_map_elt_key(i, |e| key.encode(e))); + try!(e.emit_map_elt_val(i, |e| val.encode(e))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + K: Decodable + Hash + Eq, + V: Decodable, + S, + H: Hasher + Default +> Decodable for HashMap { + fn decode(d: &mut D) -> Result, E> { + d.read_map(|d, len| { + let hasher = Default::default(); + let mut map = HashMap::with_capacity_and_hasher(len, hasher); + for i in range(0u, len) { + let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d))); + let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d))); + map.insert(key, val); + } + Ok(map) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable + Hash + Eq, + X, + H: Hasher +> Encodable for HashSet { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + let mut i = 0; + for e in self.iter() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + T: Decodable + Hash + Eq, + S, + H: Hasher + Default +> Decodable for HashSet { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut set = HashSet::with_capacity_and_hasher(len, Default::default()); + for i in range(0u, len) { + set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(set) + }) + } +} + +impl< + E, + S: Encoder, + V: Encodable +> Encodable for VecMap { + fn encode(&self, e: &mut S) -> Result<(), E> { + e.emit_map(self.len(), |e| { + for (i, (key, val)) in self.iter().enumerate() { + try!(e.emit_map_elt_key(i, |e| key.encode(e))); + try!(e.emit_map_elt_val(i, |e| val.encode(e))); + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + V: Decodable +> Decodable for VecMap { + fn decode(d: &mut D) -> Result, E> { + d.read_map(|d, len| { + let mut map = VecMap::new(); + for i in range(0u, len) { + let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d))); + let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d))); + map.insert(key, val); + } + Ok(map) + }) + } +} diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index e31d8157332c9..e8bd46815e6ac 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -300,7 +300,7 @@ pub fn error_str(error: ErrorCode) -> &'static str { } /// Shortcut function to decode a JSON `&str` into an object -pub fn decode>(s: &str) -> DecodeResult { +pub fn decode(s: &str) -> DecodeResult { let json = match from_str(s) { Ok(x) => x, Err(e) => return Err(ParseError(e)) @@ -311,9 +311,7 @@ pub fn decode>(s: &str) -> DecodeResult } /// Shortcut function to encode a `T` into a JSON `String` -pub fn encode(object: &T) -> string::String - where T: for<'a> Encodable, fmt::Error> -{ +pub fn encode(object: &T) -> string::String { let mut s = String::new(); { let mut encoder = Encoder::new(&mut s); @@ -444,7 +442,9 @@ impl<'a> Encoder<'a> { } } -impl<'a> ::Encoder for Encoder<'a> { +impl<'a> ::Encoder for Encoder<'a> { + type Error = fmt::Error; + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } @@ -664,7 +664,9 @@ impl<'a> PrettyEncoder<'a> { } } -impl<'a> ::Encoder for PrettyEncoder<'a> { +impl<'a> ::Encoder for PrettyEncoder<'a> { + type Error = fmt::Error; + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } @@ -909,8 +911,8 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { } } -impl, S> Encodable for Json { - fn encode(&self, e: &mut E) -> Result<(), S> { +impl Encodable for Json { + fn encode(&self, e: &mut E) -> Result<(), E::Error> { match *self { Json::I64(v) => v.encode(e), Json::U64(v) => v.encode(e), @@ -2062,7 +2064,9 @@ macro_rules! read_primitive { } } -impl ::Decoder for Decoder { +impl ::Decoder for Decoder { + type Error = DecoderError; + fn read_nil(&mut self) -> DecodeResult<()> { expect!(self.pop(), Null) } @@ -2474,9 +2478,7 @@ impl<'a> fmt::Show for PrettyJson<'a> { } } -impl<'a, T> fmt::Show for AsJson<'a, T> - where T: for<'b> Encodable, fmt::Error> -{ +impl<'a, T: Encodable> fmt::Show for AsJson<'a, T> { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; @@ -2493,9 +2495,7 @@ impl<'a, T> AsPrettyJson<'a, T> { } } -impl<'a, T> fmt::Show for AsPrettyJson<'a, T> - where T: for<'b> Encodable, fmt::Error> -{ +impl<'a, T: Encodable> fmt::Show for AsPrettyJson<'a, T> { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; @@ -3155,8 +3155,7 @@ mod tests { A(f64), B(string::String) } - fn check_err>(to_parse: &'static str, - expected: DecoderError) { + fn check_err(to_parse: &'static str, expected: DecoderError) { let res: DecodeResult = match from_str(to_parse) { Err(e) => Err(ParseError(e)), Ok(json) => Decodable::decode(&mut Decoder::new(json)) diff --git a/src/libserialize/json_stage0.rs b/src/libserialize/json_stage0.rs new file mode 100644 index 0000000000000..84180159c2be7 --- /dev/null +++ b/src/libserialize/json_stage0.rs @@ -0,0 +1,3883 @@ +// 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. + +// Rust JSON serialization library +// Copyright (c) 2011 Google Inc. + +#![forbid(non_camel_case_types)] +#![allow(missing_docs)] + +//! JSON parsing and serialization +//! +//! # What is JSON? +//! +//! JSON (JavaScript Object Notation) is a way to write data in Javascript. +//! Like XML, it allows to encode structured data in a text format that can be easily read by humans +//! Its simple syntax and native compatibility with JavaScript have made it a widely used format. +//! +//! Data types that can be encoded are JavaScript types (see the `Json` enum for more details): +//! +//! * `Boolean`: equivalent to rust's `bool` +//! * `Number`: equivalent to rust's `f64` +//! * `String`: equivalent to rust's `String` +//! * `Array`: equivalent to rust's `Vec`, but also allowing objects of different types in the +//! same array +//! * `Object`: equivalent to rust's `BTreeMap` +//! * `Null` +//! +//! An object is a series of string keys mapping to values, in `"key": value` format. +//! Arrays are enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }). +//! A simple JSON document encoding a person, his/her age, address and phone numbers could look like +//! +//! ```ignore +//! { +//! "FirstName": "John", +//! "LastName": "Doe", +//! "Age": 43, +//! "Address": { +//! "Street": "Downing Street 10", +//! "City": "London", +//! "Country": "Great Britain" +//! }, +//! "PhoneNumbers": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! } +//! ``` +//! +//! # Rust Type-based Encoding and Decoding +//! +//! Rust provides a mechanism for low boilerplate encoding & decoding of values to and from JSON via +//! the serialization API. +//! To be able to encode a piece of data, it must implement the `serialize::RustcEncodable` trait. +//! To be able to decode a piece of data, it must implement the `serialize::RustcDecodable` trait. +//! The Rust compiler provides an annotation to automatically generate the code for these traits: +//! `#[derive(RustcDecodable, RustcEncodable)]` +//! +//! The JSON API provides an enum `json::Json` and a trait `ToJson` to encode objects. +//! The `ToJson` trait provides a `to_json` method to convert an object into a `json::Json` value. +//! A `json::Json` value can be encoded as a string or buffer using the functions described above. +//! You can also use the `json::Encoder` object, which implements the `Encoder` trait. +//! +//! When using `ToJson` the `RustcEncodable` trait implementation is not mandatory. +//! +//! # Examples of use +//! +//! ## Using Autoserialization +//! +//! Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the +//! serialization API, using the derived serialization code. +//! +//! ```notrust +//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! extern crate serialize; +//! use serialize::json; +//! +//! // Automatically generate `Decodable` and `Encodable` trait implementations +//! #[derive(RustcDecodable, RustcEncodable)] +//! pub struct TestStruct { +//! data_int: u8, +//! data_str: String, +//! data_vector: Vec, +//! } +//! +//! fn main() { +//! let object = TestStruct { +//! data_int: 1, +//! data_str: "homura".to_string(), +//! data_vector: vec![2,3,4,5], +//! }; +//! +//! // Serialize using `json::encode` +//! let encoded = json::encode(&object); +//! +//! // Deserialize using `json::decode` +//! let decoded: TestStruct = json::decode(encoded.as_slice()).unwrap(); +//! } +//! ``` +//! +//! ## Using the `ToJson` trait +//! +//! The examples above use the `ToJson` trait to generate the JSON string, which is required +//! for custom mappings. +//! +//! ### Simple example of `ToJson` usage +//! +//! ```notrust +//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! extern crate serialize; +//! use serialize::json::{mod, ToJson, Json}; +//! +//! // A custom data structure +//! struct ComplexNum { +//! a: f64, +//! b: f64, +//! } +//! +//! // JSON value representation +//! impl ToJson for ComplexNum { +//! fn to_json(&self) -> Json { +//! Json::String(format!("{}+{}i", self.a, self.b)) +//! } +//! } +//! +//! // Only generate `RustcEncodable` trait implementation +//! #[derive(Encodable)] +//! pub struct ComplexNumRecord { +//! uid: u8, +//! dsc: String, +//! val: Json, +//! } +//! +//! fn main() { +//! let num = ComplexNum { a: 0.0001, b: 12.539 }; +//! let data: String = json::encode(&ComplexNumRecord{ +//! uid: 1, +//! dsc: "test".to_string(), +//! val: num.to_json(), +//! }); +//! println!("data: {}", data); +//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539j"}; +//! } +//! ``` +//! +//! ### Verbose example of `ToJson` usage +//! +//! ```notrust +//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! extern crate serialize; +//! use std::collections::BTreeMap; +//! use serialize::json::{mod, Json, ToJson}; +//! +//! // Only generate `Decodable` trait implementation +//! #[derive(Decodable)] +//! pub struct TestStruct { +//! data_int: u8, +//! data_str: String, +//! data_vector: Vec, +//! } +//! +//! // Specify encoding method manually +//! impl ToJson for TestStruct { +//! fn to_json(&self) -> Json { +//! let mut d = BTreeMap::new(); +//! // All standard types implement `to_json()`, so use it +//! d.insert("data_int".to_string(), self.data_int.to_json()); +//! d.insert("data_str".to_string(), self.data_str.to_json()); +//! d.insert("data_vector".to_string(), self.data_vector.to_json()); +//! Json::Object(d) +//! } +//! } +//! +//! fn main() { +//! // Serialize using `ToJson` +//! let input_data = TestStruct { +//! data_int: 1, +//! data_str: "madoka".to_string(), +//! data_vector: vec![2,3,4,5], +//! }; +//! let json_obj: Json = input_data.to_json(); +//! let json_str: String = json_obj.to_string(); +//! +//! // Deserialize like before +//! let decoded: TestStruct = json::decode(json_str.as_slice()).unwrap(); +//! } +//! ``` + +use self::JsonEvent::*; +use self::StackElement::*; +use self::ErrorCode::*; +use self::ParserError::*; +use self::DecoderError::*; +use self::ParserState::*; +use self::InternalStackElement::*; + +use std; +use std::collections::{HashMap, BTreeMap}; +use std::{char, f64, fmt, io, num, str}; +use std::mem::{swap, transmute}; +use std::num::{Float, Int}; +use std::num::FpCategory as Fp; +use std::str::FromStr; +use std::string; +use std::ops; +use unicode::str as unicode_str; +use unicode::str::Utf16Item; + +use Encodable; + +/// Represents a json value +#[derive(Clone, PartialEq, PartialOrd)] +pub enum Json { + I64(i64), + U64(u64), + F64(f64), + String(string::String), + Boolean(bool), + Array(self::Array), + Object(self::Object), + Null, +} + +pub type Array = Vec; +pub type Object = BTreeMap; + +pub struct PrettyJson<'a> { inner: &'a Json } + +pub struct AsJson<'a, T: 'a> { inner: &'a T } +pub struct AsPrettyJson<'a, T: 'a> { inner: &'a T, indent: Option } + +/// The errors that can arise while parsing a JSON stream. +#[derive(Clone, Copy, PartialEq)] +pub enum ErrorCode { + InvalidSyntax, + InvalidNumber, + EOFWhileParsingObject, + EOFWhileParsingArray, + EOFWhileParsingValue, + EOFWhileParsingString, + KeyMustBeAString, + ExpectedColon, + TrailingCharacters, + TrailingComma, + InvalidEscape, + InvalidUnicodeCodePoint, + LoneLeadingSurrogateInHexEscape, + UnexpectedEndOfHexEscape, + UnrecognizedHex, + NotFourDigit, + NotUtf8, +} + +#[derive(Clone, Copy, PartialEq, Show)] +pub enum ParserError { + /// msg, line, col + SyntaxError(ErrorCode, uint, uint), + IoError(io::IoErrorKind, &'static str), +} + +// Builder and Parser have the same errors. +pub type BuilderError = ParserError; + +#[derive(Clone, PartialEq, Show)] +pub enum DecoderError { + ParseError(ParserError), + ExpectedError(string::String, string::String), + MissingFieldError(string::String), + UnknownVariantError(string::String), + ApplicationError(string::String) +} + +/// Returns a readable error string for a given error code. +pub fn error_str(error: ErrorCode) -> &'static str { + match error { + InvalidSyntax => "invalid syntax", + InvalidNumber => "invalid number", + EOFWhileParsingObject => "EOF While parsing object", + EOFWhileParsingArray => "EOF While parsing array", + EOFWhileParsingValue => "EOF While parsing value", + EOFWhileParsingString => "EOF While parsing string", + KeyMustBeAString => "key must be a string", + ExpectedColon => "expected `:`", + TrailingCharacters => "trailing characters", + TrailingComma => "trailing comma", + InvalidEscape => "invalid escape", + UnrecognizedHex => "invalid \\u{ esc}ape (unrecognized hex)", + NotFourDigit => "invalid \\u{ esc}ape (not four digits)", + NotUtf8 => "contents not utf-8", + InvalidUnicodeCodePoint => "invalid Unicode code point", + LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape", + UnexpectedEndOfHexEscape => "unexpected end of hex escape", + } +} + +/// Shortcut function to decode a JSON `&str` into an object +pub fn decode>(s: &str) -> DecodeResult { + let json = match from_str(s) { + Ok(x) => x, + Err(e) => return Err(ParseError(e)) + }; + + let mut decoder = Decoder::new(json); + ::Decodable::decode(&mut decoder) +} + +/// Shortcut function to encode a `T` into a JSON `String` +pub fn encode(object: &T) -> string::String + where T: for<'a> Encodable, fmt::Error> +{ + let mut s = String::new(); + { + let mut encoder = Encoder::new(&mut s); + let _ = object.encode(&mut encoder); + } + s +} + +impl fmt::Show for ErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + error_str(*self).fmt(f) + } +} + +fn io_error_to_error(io: io::IoError) -> ParserError { + IoError(io.kind, io.desc) +} + +impl std::error::Error for DecoderError { + fn description(&self) -> &str { "decoder error" } + fn detail(&self) -> Option { Some(self.to_string()) } +} + +pub type EncodeResult = fmt::Result; +pub type DecodeResult = Result; + +fn escape_str(wr: &mut fmt::Writer, v: &str) -> fmt::Result { + try!(wr.write_str("\"")); + + let mut start = 0; + + for (i, byte) in v.bytes().enumerate() { + let escaped = match byte { + b'"' => "\\\"", + b'\\' => "\\\\", + b'\x00' => "\\u0000", + b'\x01' => "\\u0001", + b'\x02' => "\\u0002", + b'\x03' => "\\u0003", + b'\x04' => "\\u0004", + b'\x05' => "\\u0005", + b'\x06' => "\\u0006", + b'\x07' => "\\u0007", + b'\x08' => "\\b", + b'\t' => "\\t", + b'\n' => "\\n", + b'\x0b' => "\\u000b", + b'\x0c' => "\\f", + b'\r' => "\\r", + b'\x0e' => "\\u000e", + b'\x0f' => "\\u000f", + b'\x10' => "\\u0010", + b'\x11' => "\\u0011", + b'\x12' => "\\u0012", + b'\x13' => "\\u0013", + b'\x14' => "\\u0014", + b'\x15' => "\\u0015", + b'\x16' => "\\u0016", + b'\x17' => "\\u0017", + b'\x18' => "\\u0018", + b'\x19' => "\\u0019", + b'\x1a' => "\\u001a", + b'\x1b' => "\\u001b", + b'\x1c' => "\\u001c", + b'\x1d' => "\\u001d", + b'\x1e' => "\\u001e", + b'\x1f' => "\\u001f", + b'\x7f' => "\\u007f", + _ => { continue; } + }; + + if start < i { + try!(wr.write_str(v[start..i])); + } + + try!(wr.write_str(escaped)); + + start = i + 1; + } + + if start != v.len() { + try!(wr.write_str(v[start..])); + } + + wr.write_str("\"") +} + +fn escape_char(writer: &mut fmt::Writer, v: char) -> fmt::Result { + let mut buf = [0; 4]; + let n = v.encode_utf8(&mut buf).unwrap(); + let buf = unsafe { str::from_utf8_unchecked(buf[0..n]) }; + escape_str(writer, buf) +} + +fn spaces(wr: &mut fmt::Writer, mut n: uint) -> fmt::Result { + const BUF: &'static str = " "; + + while n >= BUF.len() { + try!(wr.write_str(BUF)); + n -= BUF.len(); + } + + if n > 0 { + wr.write_str(BUF[..n]) + } else { + Ok(()) + } +} + +fn fmt_number_or_null(v: f64) -> string::String { + match v.classify() { + Fp::Nan | Fp::Infinite => string::String::from_str("null"), + _ if v.fract() != 0f64 => f64::to_str_digits(v, 6u), + _ => f64::to_str_digits(v, 6u) + ".0", + } +} + +/// A structure for implementing serialization to JSON. +pub struct Encoder<'a> { + writer: &'a mut (fmt::Writer+'a), +} + +impl<'a> Encoder<'a> { + /// Creates a new JSON encoder whose output will be written to the writer + /// specified. + pub fn new(writer: &'a mut fmt::Writer) -> Encoder<'a> { + Encoder { writer: writer } + } +} + +impl<'a> ::Encoder for Encoder<'a> { + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } + + fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u64(&mut self, v: u64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u32(&mut self, v: u32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u16(&mut self, v: u16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u8(&mut self, v: u8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_int(&mut self, v: int) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i64(&mut self, v: i64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i32(&mut self, v: i32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i16(&mut self, v: i16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i8(&mut self, v: i8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_bool(&mut self, v: bool) -> EncodeResult { + if v { + write!(self.writer, "true") + } else { + write!(self.writer, "false") + } + } + + fn emit_f64(&mut self, v: f64) -> EncodeResult { + write!(self.writer, "{}", fmt_number_or_null(v)) + } + fn emit_f32(&mut self, v: f32) -> EncodeResult { + self.emit_f64(v as f64) + } + + fn emit_char(&mut self, v: char) -> EncodeResult { + escape_char(self.writer, v) + } + fn emit_str(&mut self, v: &str) -> EncodeResult { + escape_str(self.writer, v) + } + + fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_enum_variant(&mut self, + name: &str, + _id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + // enums are encoded as strings or objects + // Bunny => "Bunny" + // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]} + if cnt == 0 { + escape_str(self.writer, name) + } else { + try!(write!(self.writer, "{{\"variant\":")); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ",\"fields\":[")); + try!(f(self)); + write!(self.writer, "]}}") + } + } + + fn emit_enum_variant_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { + try!(write!(self.writer, ",")); + } + f(self) + } + + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&mut self, _: &str, _: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, "{{")); + try!(f(self)); + write!(self.writer, "}}") + } + + fn emit_struct_field(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { try!(write!(self.writer, ",")); } + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ":")); + f(self) + } + + fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, _name: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + f(self) + } + fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() } + fn emit_option_some(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_seq(&mut self, _len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, "[")); + try!(f(self)); + write!(self.writer, "]") + } + + fn emit_seq_elt(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { + try!(write!(self.writer, ",")); + } + f(self) + } + + fn emit_map(&mut self, _len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, "{{")); + try!(f(self)); + write!(self.writer, "}}") + } + + fn emit_map_elt_key(&mut self, idx: uint, mut f: F) -> EncodeResult where + F: FnMut(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { try!(write!(self.writer, ",")) } + // ref #12967, make sure to wrap a key in double quotes, + // in the event that its of a type that omits them (eg numbers) + let mut buf = Vec::new(); + // FIXME(14302) remove the transmute and unsafe block. + unsafe { + let mut check_encoder = Encoder::new(&mut buf); + try!(f(transmute(&mut check_encoder))); + } + let out = str::from_utf8(buf[]).unwrap(); + let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"'; + if needs_wrapping { try!(write!(self.writer, "\"")); } + try!(f(self)); + if needs_wrapping { try!(write!(self.writer, "\"")); } + Ok(()) + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, ":")); + f(self) + } +} + +/// Another encoder for JSON, but prints out human-readable JSON instead of +/// compact data +pub struct PrettyEncoder<'a> { + writer: &'a mut (fmt::Writer+'a), + curr_indent: uint, + indent: uint, +} + +impl<'a> PrettyEncoder<'a> { + /// Creates a new encoder whose output will be written to the specified writer + pub fn new(writer: &'a mut fmt::Writer) -> PrettyEncoder<'a> { + PrettyEncoder { writer: writer, curr_indent: 0, indent: 2, } + } + + /// Set the number of spaces to indent for each level. + /// This is safe to set during encoding. + pub fn set_indent(&mut self, indent: uint) { + // self.indent very well could be 0 so we need to use checked division. + let level = self.curr_indent.checked_div(self.indent).unwrap_or(0); + self.indent = indent; + self.curr_indent = level * self.indent; + } +} + +impl<'a> ::Encoder for PrettyEncoder<'a> { + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } + + fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u64(&mut self, v: u64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u32(&mut self, v: u32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u16(&mut self, v: u16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u8(&mut self, v: u8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_int(&mut self, v: int) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i64(&mut self, v: i64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i32(&mut self, v: i32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i16(&mut self, v: i16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i8(&mut self, v: i8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_bool(&mut self, v: bool) -> EncodeResult { + if v { + write!(self.writer, "true") + } else { + write!(self.writer, "false") + } + } + + fn emit_f64(&mut self, v: f64) -> EncodeResult { + write!(self.writer, "{}", fmt_number_or_null(v)) + } + fn emit_f32(&mut self, v: f32) -> EncodeResult { + self.emit_f64(v as f64) + } + + fn emit_char(&mut self, v: char) -> EncodeResult { + escape_char(self.writer, v) + } + fn emit_str(&mut self, v: &str) -> EncodeResult { + escape_str(self.writer, v) + } + + fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_enum_variant(&mut self, + name: &str, + _id: uint, + cnt: uint, + f: F) + -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if cnt == 0 { + escape_str(self.writer, name) + } else { + try!(write!(self.writer, "{{\n")); + self.curr_indent += self.indent; + try!(spaces(self.writer, self.curr_indent)); + try!(write!(self.writer, "\"variant\": ")); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ",\n")); + try!(spaces(self.writer, self.curr_indent)); + try!(write!(self.writer, "\"fields\": [\n")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "]\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "}}") + } + } + + fn emit_enum_variant_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx != 0 { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + f(self) + } + + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_enum_variant_arg(idx, f) + } + + + fn emit_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if len == 0 { + write!(self.writer, "{{}}") + } else { + try!(write!(self.writer, "{{")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "}}") + } + } + + fn emit_struct_field(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx == 0 { + try!(write!(self.writer, "\n")); + } else { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ": ")); + f(self) + } + + fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + f(self) + } + fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() } + fn emit_option_some(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_seq(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if len == 0 { + write!(self.writer, "[]") + } else { + try!(write!(self.writer, "[")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "]") + } + } + + fn emit_seq_elt(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx == 0 { + try!(write!(self.writer, "\n")); + } else { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + f(self) + } + + fn emit_map(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if len == 0 { + write!(self.writer, "{{}}") + } else { + try!(write!(self.writer, "{{")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "}}") + } + } + + fn emit_map_elt_key(&mut self, idx: uint, mut f: F) -> EncodeResult where + F: FnMut(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx == 0 { + try!(write!(self.writer, "\n")); + } else { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + // ref #12967, make sure to wrap a key in double quotes, + // in the event that its of a type that omits them (eg numbers) + let mut buf = Vec::new(); + // FIXME(14302) remove the transmute and unsafe block. + unsafe { + let mut check_encoder = PrettyEncoder::new(&mut buf); + try!(f(transmute(&mut check_encoder))); + } + let out = str::from_utf8(buf[]).unwrap(); + let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"'; + if needs_wrapping { try!(write!(self.writer, "\"")); } + try!(f(self)); + if needs_wrapping { try!(write!(self.writer, "\"")); } + Ok(()) + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, ": ")); + f(self) + } +} + +impl, S> Encodable for Json { + fn encode(&self, e: &mut E) -> Result<(), S> { + match *self { + Json::I64(v) => v.encode(e), + Json::U64(v) => v.encode(e), + Json::F64(v) => v.encode(e), + Json::String(ref v) => v.encode(e), + Json::Boolean(v) => v.encode(e), + Json::Array(ref v) => v.encode(e), + Json::Object(ref v) => v.encode(e), + Json::Null => e.emit_nil(), + } + } +} + +/// Create an `AsJson` wrapper which can be used to print a value as JSON +/// on-the-fly via `write!` +pub fn as_json(t: &T) -> AsJson { + AsJson { inner: t } +} + +/// Create an `AsPrettyJson` wrapper which can be used to print a value as JSON +/// on-the-fly via `write!` +pub fn as_pretty_json(t: &T) -> AsPrettyJson { + AsPrettyJson { inner: t, indent: None } +} + +impl Json { + /// Borrow this json object as a pretty object to generate a pretty + /// representation for it via `Show`. + pub fn pretty(&self) -> PrettyJson { + PrettyJson { inner: self } + } + + /// If the Json value is an Object, returns the value associated with the provided key. + /// Otherwise, returns None. + pub fn find<'a>(&'a self, key: &str) -> Option<&'a Json>{ + match self { + &Json::Object(ref map) => map.get(key), + _ => None + } + } + + /// Attempts to get a nested Json Object for each key in `keys`. + /// If any key is found not to exist, find_path will return None. + /// Otherwise, it will return the Json value associated with the final key. + pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Json>{ + let mut target = self; + for key in keys.iter() { + match target.find(*key) { + Some(t) => { target = t; }, + None => return None + } + } + Some(target) + } + + /// If the Json value is an Object, performs a depth-first search until + /// a value associated with the provided key is found. If no value is found + /// or the Json value is not an Object, returns None. + pub fn search<'a>(&'a self, key: &str) -> Option<&'a Json> { + match self { + &Json::Object(ref map) => { + match map.get(key) { + Some(json_value) => Some(json_value), + None => { + for (_, v) in map.iter() { + match v.search(key) { + x if x.is_some() => return x, + _ => () + } + } + None + } + } + }, + _ => None + } + } + + /// Returns true if the Json value is an Object. Returns false otherwise. + pub fn is_object<'a>(&'a self) -> bool { + self.as_object().is_some() + } + + /// If the Json value is an Object, returns the associated BTreeMap. + /// Returns None otherwise. + pub fn as_object<'a>(&'a self) -> Option<&'a Object> { + match self { + &Json::Object(ref map) => Some(map), + _ => None + } + } + + /// Returns true if the Json value is an Array. Returns false otherwise. + pub fn is_array<'a>(&'a self) -> bool { + self.as_array().is_some() + } + + /// If the Json value is an Array, returns the associated vector. + /// Returns None otherwise. + pub fn as_array<'a>(&'a self) -> Option<&'a Array> { + match self { + &Json::Array(ref array) => Some(&*array), + _ => None + } + } + + /// Returns true if the Json value is a String. Returns false otherwise. + pub fn is_string<'a>(&'a self) -> bool { + self.as_string().is_some() + } + + /// If the Json value is a String, returns the associated str. + /// Returns None otherwise. + pub fn as_string<'a>(&'a self) -> Option<&'a str> { + match *self { + Json::String(ref s) => Some(s[]), + _ => None + } + } + + /// Returns true if the Json value is a Number. Returns false otherwise. + pub fn is_number(&self) -> bool { + match *self { + Json::I64(_) | Json::U64(_) | Json::F64(_) => true, + _ => false, + } + } + + /// Returns true if the Json value is a i64. Returns false otherwise. + pub fn is_i64(&self) -> bool { + match *self { + Json::I64(_) => true, + _ => false, + } + } + + /// Returns true if the Json value is a u64. Returns false otherwise. + pub fn is_u64(&self) -> bool { + match *self { + Json::U64(_) => true, + _ => false, + } + } + + /// Returns true if the Json value is a f64. Returns false otherwise. + pub fn is_f64(&self) -> bool { + match *self { + Json::F64(_) => true, + _ => false, + } + } + + /// If the Json value is a number, return or cast it to a i64. + /// Returns None otherwise. + pub fn as_i64(&self) -> Option { + match *self { + Json::I64(n) => Some(n), + Json::U64(n) => num::cast(n), + _ => None + } + } + + /// If the Json value is a number, return or cast it to a u64. + /// Returns None otherwise. + pub fn as_u64(&self) -> Option { + match *self { + Json::I64(n) => num::cast(n), + Json::U64(n) => Some(n), + _ => None + } + } + + /// If the Json value is a number, return or cast it to a f64. + /// Returns None otherwise. + pub fn as_f64(&self) -> Option { + match *self { + Json::I64(n) => num::cast(n), + Json::U64(n) => num::cast(n), + Json::F64(n) => Some(n), + _ => None + } + } + + /// Returns true if the Json value is a Boolean. Returns false otherwise. + pub fn is_boolean(&self) -> bool { + self.as_boolean().is_some() + } + + /// If the Json value is a Boolean, returns the associated bool. + /// Returns None otherwise. + pub fn as_boolean(&self) -> Option { + match self { + &Json::Boolean(b) => Some(b), + _ => None + } + } + + /// Returns true if the Json value is a Null. Returns false otherwise. + pub fn is_null(&self) -> bool { + self.as_null().is_some() + } + + /// If the Json value is a Null, returns (). + /// Returns None otherwise. + pub fn as_null(&self) -> Option<()> { + match self { + &Json::Null => Some(()), + _ => None + } + } +} + +// NOTE(stage0): remove impl after a snapshot +#[cfg(stage0)] +impl<'a> ops::Index<&'a str, Json> for Json { + fn index(&self, idx: & &str) -> &Json { + self.find(*idx).unwrap() + } +} + +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +impl<'a> ops::Index<&'a str> for Json { + type Output = Json; + + fn index(&self, idx: & &str) -> &Json { + self.find(*idx).unwrap() + } +} + +// NOTE(stage0): remove impl after a snapshot +#[cfg(stage0)] +impl ops::Index for Json { + fn index<'a>(&'a self, idx: &uint) -> &'a Json { + match self { + &Json::Array(ref v) => v.index(idx), + _ => panic!("can only index Json with uint if it is an array") + } + } +} + +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +impl ops::Index for Json { + type Output = Json; + + fn index<'a>(&'a self, idx: &uint) -> &'a Json { + match self { + &Json::Array(ref v) => v.index(idx), + _ => panic!("can only index Json with uint if it is an array") + } + } +} + +/// The output of the streaming parser. +#[derive(PartialEq, Clone, Show)] +pub enum JsonEvent { + ObjectStart, + ObjectEnd, + ArrayStart, + ArrayEnd, + BooleanValue(bool), + I64Value(i64), + U64Value(u64), + F64Value(f64), + StringValue(string::String), + NullValue, + Error(ParserError), +} + +#[derive(PartialEq, Show)] +enum ParserState { + // Parse a value in an array, true means first element. + ParseArray(bool), + // Parse ',' or ']' after an element in an array. + ParseArrayComma, + // Parse a key:value in an object, true means first element. + ParseObject(bool), + // Parse ',' or ']' after an element in an object. + ParseObjectComma, + // Initial state. + ParseStart, + // Expecting the stream to end. + ParseBeforeFinish, + // Parsing can't continue. + ParseFinished, +} + +/// A Stack represents the current position of the parser in the logical +/// structure of the JSON stream. +/// For example foo.bar[3].x +pub struct Stack { + stack: Vec, + str_buffer: Vec, +} + +/// StackElements compose a Stack. +/// For example, Key("foo"), Key("bar"), Index(3) and Key("x") are the +/// StackElements compositing the stack that represents foo.bar[3].x +#[derive(PartialEq, Clone, Show)] +pub enum StackElement<'l> { + Index(u32), + Key(&'l str), +} + +// Internally, Key elements are stored as indices in a buffer to avoid +// allocating a string for every member of an object. +#[derive(PartialEq, Clone, Show)] +enum InternalStackElement { + InternalIndex(u32), + InternalKey(u16, u16), // start, size +} + +impl Stack { + pub fn new() -> Stack { + Stack { stack: Vec::new(), str_buffer: Vec::new() } + } + + /// Returns The number of elements in the Stack. + pub fn len(&self) -> uint { self.stack.len() } + + /// Returns true if the stack is empty. + pub fn is_empty(&self) -> bool { self.stack.is_empty() } + + /// Provides access to the StackElement at a given index. + /// lower indices are at the bottom of the stack while higher indices are + /// at the top. + pub fn get<'l>(&'l self, idx: uint) -> StackElement<'l> { + match self.stack[idx] { + InternalIndex(i) => Index(i), + InternalKey(start, size) => { + Key(str::from_utf8( + self.str_buffer[start as uint .. start as uint + size as uint]).unwrap()) + } + } + } + + /// Compares this stack with an array of StackElements. + pub fn is_equal_to(&self, rhs: &[StackElement]) -> bool { + if self.stack.len() != rhs.len() { return false; } + for i in range(0, rhs.len()) { + if self.get(i) != rhs[i] { return false; } + } + return true; + } + + /// Returns true if the bottom-most elements of this stack are the same as + /// the ones passed as parameter. + pub fn starts_with(&self, rhs: &[StackElement]) -> bool { + if self.stack.len() < rhs.len() { return false; } + for i in range(0, rhs.len()) { + if self.get(i) != rhs[i] { return false; } + } + return true; + } + + /// Returns true if the top-most elements of this stack are the same as + /// the ones passed as parameter. + pub fn ends_with(&self, rhs: &[StackElement]) -> bool { + if self.stack.len() < rhs.len() { return false; } + let offset = self.stack.len() - rhs.len(); + for i in range(0, rhs.len()) { + if self.get(i + offset) != rhs[i] { return false; } + } + return true; + } + + /// Returns the top-most element (if any). + pub fn top<'l>(&'l self) -> Option> { + return match self.stack.last() { + None => None, + Some(&InternalIndex(i)) => Some(Index(i)), + Some(&InternalKey(start, size)) => { + Some(Key(str::from_utf8( + self.str_buffer[start as uint .. (start+size) as uint] + ).unwrap())) + } + } + } + + // Used by Parser to insert Key elements at the top of the stack. + fn push_key(&mut self, key: string::String) { + self.stack.push(InternalKey(self.str_buffer.len() as u16, key.len() as u16)); + for c in key.as_bytes().iter() { + self.str_buffer.push(*c); + } + } + + // Used by Parser to insert Index elements at the top of the stack. + fn push_index(&mut self, index: u32) { + self.stack.push(InternalIndex(index)); + } + + // Used by Parser to remove the top-most element of the stack. + fn pop(&mut self) { + assert!(!self.is_empty()); + match *self.stack.last().unwrap() { + InternalKey(_, sz) => { + let new_size = self.str_buffer.len() - sz as uint; + self.str_buffer.truncate(new_size); + } + InternalIndex(_) => {} + } + self.stack.pop(); + } + + // Used by Parser to test whether the top-most element is an index. + fn last_is_index(&self) -> bool { + if self.is_empty() { return false; } + return match *self.stack.last().unwrap() { + InternalIndex(_) => true, + _ => false, + } + } + + // Used by Parser to increment the index of the top-most element. + fn bump_index(&mut self) { + let len = self.stack.len(); + let idx = match *self.stack.last().unwrap() { + InternalIndex(i) => { i + 1 } + _ => { panic!(); } + }; + self.stack[len - 1] = InternalIndex(idx); + } +} + +/// A streaming JSON parser implemented as an iterator of JsonEvent, consuming +/// an iterator of char. +pub struct Parser { + rdr: T, + ch: Option, + line: uint, + col: uint, + // We maintain a stack representing where we are in the logical structure + // of the JSON stream. + stack: Stack, + // A state machine is kept to make it possible to interrupt and resume parsing. + state: ParserState, +} + +impl> Iterator for Parser { + type Item = JsonEvent; + + fn next(&mut self) -> Option { + if self.state == ParseFinished { + return None; + } + + if self.state == ParseBeforeFinish { + self.parse_whitespace(); + // Make sure there is no trailing characters. + if self.eof() { + self.state = ParseFinished; + return None; + } else { + return Some(self.error_event(TrailingCharacters)); + } + } + + return Some(self.parse()); + } +} + +impl> Parser { + /// Creates the JSON parser. + pub fn new(rdr: T) -> Parser { + let mut p = Parser { + rdr: rdr, + ch: Some('\x00'), + line: 1, + col: 0, + stack: Stack::new(), + state: ParseStart, + }; + p.bump(); + return p; + } + + /// Provides access to the current position in the logical structure of the + /// JSON stream. + pub fn stack<'l>(&'l self) -> &'l Stack { + return &self.stack; + } + + fn eof(&self) -> bool { self.ch.is_none() } + fn ch_or_null(&self) -> char { self.ch.unwrap_or('\x00') } + fn bump(&mut self) { + self.ch = self.rdr.next(); + + if self.ch_is('\n') { + self.line += 1u; + self.col = 1u; + } else { + self.col += 1u; + } + } + + fn next_char(&mut self) -> Option { + self.bump(); + self.ch + } + fn ch_is(&self, c: char) -> bool { + self.ch == Some(c) + } + + fn error(&self, reason: ErrorCode) -> Result { + Err(SyntaxError(reason, self.line, self.col)) + } + + fn parse_whitespace(&mut self) { + while self.ch_is(' ') || + self.ch_is('\n') || + self.ch_is('\t') || + self.ch_is('\r') { self.bump(); } + } + + fn parse_number(&mut self) -> JsonEvent { + let mut neg = false; + + if self.ch_is('-') { + self.bump(); + neg = true; + } + + let res = match self.parse_u64() { + Ok(res) => res, + Err(e) => { return Error(e); } + }; + + if self.ch_is('.') || self.ch_is('e') || self.ch_is('E') { + let mut res = res as f64; + + if self.ch_is('.') { + res = match self.parse_decimal(res) { + Ok(res) => res, + Err(e) => { return Error(e); } + }; + } + + if self.ch_is('e') || self.ch_is('E') { + res = match self.parse_exponent(res) { + Ok(res) => res, + Err(e) => { return Error(e); } + }; + } + + if neg { + res *= -1.0; + } + + F64Value(res) + } else { + if neg { + let res = -(res as i64); + + // Make sure we didn't underflow. + if res > 0 { + Error(SyntaxError(InvalidNumber, self.line, self.col)) + } else { + I64Value(res) + } + } else { + U64Value(res) + } + } + } + + fn parse_u64(&mut self) -> Result { + let mut accum = 0; + let last_accum = 0; // necessary to detect overflow. + + match self.ch_or_null() { + '0' => { + self.bump(); + + // A leading '0' must be the only digit before the decimal point. + match self.ch_or_null() { + '0' ... '9' => return self.error(InvalidNumber), + _ => () + } + }, + '1' ... '9' => { + while !self.eof() { + match self.ch_or_null() { + c @ '0' ... '9' => { + accum *= 10; + accum += (c as u64) - ('0' as u64); + + // Detect overflow by comparing to the last value. + if accum <= last_accum { return self.error(InvalidNumber); } + + self.bump(); + } + _ => break, + } + } + } + _ => return self.error(InvalidNumber), + } + + Ok(accum) + } + + fn parse_decimal(&mut self, mut res: f64) -> Result { + self.bump(); + + // Make sure a digit follows the decimal place. + match self.ch_or_null() { + '0' ... '9' => (), + _ => return self.error(InvalidNumber) + } + + let mut dec = 1.0; + while !self.eof() { + match self.ch_or_null() { + c @ '0' ... '9' => { + dec /= 10.0; + res += (((c as int) - ('0' as int)) as f64) * dec; + self.bump(); + } + _ => break, + } + } + + Ok(res) + } + + fn parse_exponent(&mut self, mut res: f64) -> Result { + self.bump(); + + let mut exp = 0u; + let mut neg_exp = false; + + if self.ch_is('+') { + self.bump(); + } else if self.ch_is('-') { + self.bump(); + neg_exp = true; + } + + // Make sure a digit follows the exponent place. + match self.ch_or_null() { + '0' ... '9' => (), + _ => return self.error(InvalidNumber) + } + while !self.eof() { + match self.ch_or_null() { + c @ '0' ... '9' => { + exp *= 10; + exp += (c as uint) - ('0' as uint); + + self.bump(); + } + _ => break + } + } + + let exp = 10_f64.powi(exp as i32); + if neg_exp { + res /= exp; + } else { + res *= exp; + } + + Ok(res) + } + + fn decode_hex_escape(&mut self) -> Result { + let mut i = 0u; + let mut n = 0u16; + while i < 4 && !self.eof() { + self.bump(); + n = match self.ch_or_null() { + c @ '0' ... '9' => n * 16 + ((c as u16) - ('0' as u16)), + 'a' | 'A' => n * 16 + 10, + 'b' | 'B' => n * 16 + 11, + 'c' | 'C' => n * 16 + 12, + 'd' | 'D' => n * 16 + 13, + 'e' | 'E' => n * 16 + 14, + 'f' | 'F' => n * 16 + 15, + _ => return self.error(InvalidEscape) + }; + + i += 1u; + } + + // Error out if we didn't parse 4 digits. + if i != 4 { + return self.error(InvalidEscape); + } + + Ok(n) + } + + fn parse_str(&mut self) -> Result { + let mut escape = false; + let mut res = string::String::new(); + + loop { + self.bump(); + if self.eof() { + return self.error(EOFWhileParsingString); + } + + if escape { + match self.ch_or_null() { + '"' => res.push('"'), + '\\' => res.push('\\'), + '/' => res.push('/'), + 'b' => res.push('\x08'), + 'f' => res.push('\x0c'), + 'n' => res.push('\n'), + 'r' => res.push('\r'), + 't' => res.push('\t'), + 'u' => match try!(self.decode_hex_escape()) { + 0xDC00 ... 0xDFFF => { + return self.error(LoneLeadingSurrogateInHexEscape) + } + + // Non-BMP characters are encoded as a sequence of + // two hex escapes, representing UTF-16 surrogates. + n1 @ 0xD800 ... 0xDBFF => { + match (self.next_char(), self.next_char()) { + (Some('\\'), Some('u')) => (), + _ => return self.error(UnexpectedEndOfHexEscape), + } + + let buf = [n1, try!(self.decode_hex_escape())]; + match unicode_str::utf16_items(&buf).next() { + Some(Utf16Item::ScalarValue(c)) => res.push(c), + _ => return self.error(LoneLeadingSurrogateInHexEscape), + } + } + + n => match char::from_u32(n as u32) { + Some(c) => res.push(c), + None => return self.error(InvalidUnicodeCodePoint), + }, + }, + _ => return self.error(InvalidEscape), + } + escape = false; + } else if self.ch_is('\\') { + escape = true; + } else { + match self.ch { + Some('"') => { + self.bump(); + return Ok(res); + }, + Some(c) => res.push(c), + None => unreachable!() + } + } + } + } + + // Invoked at each iteration, consumes the stream until it has enough + // information to return a JsonEvent. + // Manages an internal state so that parsing can be interrupted and resumed. + // Also keeps track of the position in the logical structure of the json + // stream int the form of a stack that can be queried by the user using the + // stack() method. + fn parse(&mut self) -> JsonEvent { + loop { + // The only paths where the loop can spin a new iteration + // are in the cases ParseArrayComma and ParseObjectComma if ',' + // is parsed. In these cases the state is set to (respectively) + // ParseArray(false) and ParseObject(false), which always return, + // so there is no risk of getting stuck in an infinite loop. + // All other paths return before the end of the loop's iteration. + self.parse_whitespace(); + + match self.state { + ParseStart => { + return self.parse_start(); + } + ParseArray(first) => { + return self.parse_array(first); + } + ParseArrayComma => { + match self.parse_array_comma_or_end() { + Some(evt) => { return evt; } + None => {} + } + } + ParseObject(first) => { + return self.parse_object(first); + } + ParseObjectComma => { + self.stack.pop(); + if self.ch_is(',') { + self.state = ParseObject(false); + self.bump(); + } else { + return self.parse_object_end(); + } + } + _ => { + return self.error_event(InvalidSyntax); + } + } + } + } + + fn parse_start(&mut self) -> JsonEvent { + let val = self.parse_value(); + self.state = match val { + Error(_) => ParseFinished, + ArrayStart => ParseArray(true), + ObjectStart => ParseObject(true), + _ => ParseBeforeFinish, + }; + return val; + } + + fn parse_array(&mut self, first: bool) -> JsonEvent { + if self.ch_is(']') { + if !first { + self.error_event(InvalidSyntax) + } else { + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + ArrayEnd + } + } else { + if first { + self.stack.push_index(0); + } + let val = self.parse_value(); + self.state = match val { + Error(_) => ParseFinished, + ArrayStart => ParseArray(true), + ObjectStart => ParseObject(true), + _ => ParseArrayComma, + }; + val + } + } + + fn parse_array_comma_or_end(&mut self) -> Option { + if self.ch_is(',') { + self.stack.bump_index(); + self.state = ParseArray(false); + self.bump(); + None + } else if self.ch_is(']') { + self.stack.pop(); + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + Some(ArrayEnd) + } else if self.eof() { + Some(self.error_event(EOFWhileParsingArray)) + } else { + Some(self.error_event(InvalidSyntax)) + } + } + + fn parse_object(&mut self, first: bool) -> JsonEvent { + if self.ch_is('}') { + if !first { + if self.stack.is_empty() { + return self.error_event(TrailingComma); + } else { + self.stack.pop(); + } + } + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + return ObjectEnd; + } + if self.eof() { + return self.error_event(EOFWhileParsingObject); + } + if !self.ch_is('"') { + return self.error_event(KeyMustBeAString); + } + let s = match self.parse_str() { + Ok(s) => s, + Err(e) => { + self.state = ParseFinished; + return Error(e); + } + }; + self.parse_whitespace(); + if self.eof() { + return self.error_event(EOFWhileParsingObject); + } else if self.ch_or_null() != ':' { + return self.error_event(ExpectedColon); + } + self.stack.push_key(s); + self.bump(); + self.parse_whitespace(); + + let val = self.parse_value(); + + self.state = match val { + Error(_) => ParseFinished, + ArrayStart => ParseArray(true), + ObjectStart => ParseObject(true), + _ => ParseObjectComma, + }; + return val; + } + + fn parse_object_end(&mut self) -> JsonEvent { + if self.ch_is('}') { + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + ObjectEnd + } else if self.eof() { + self.error_event(EOFWhileParsingObject) + } else { + self.error_event(InvalidSyntax) + } + } + + fn parse_value(&mut self) -> JsonEvent { + if self.eof() { return self.error_event(EOFWhileParsingValue); } + match self.ch_or_null() { + 'n' => { self.parse_ident("ull", NullValue) } + 't' => { self.parse_ident("rue", BooleanValue(true)) } + 'f' => { self.parse_ident("alse", BooleanValue(false)) } + '0' ... '9' | '-' => self.parse_number(), + '"' => match self.parse_str() { + Ok(s) => StringValue(s), + Err(e) => Error(e), + }, + '[' => { + self.bump(); + ArrayStart + } + '{' => { + self.bump(); + ObjectStart + } + _ => { self.error_event(InvalidSyntax) } + } + } + + fn parse_ident(&mut self, ident: &str, value: JsonEvent) -> JsonEvent { + if ident.chars().all(|c| Some(c) == self.next_char()) { + self.bump(); + value + } else { + Error(SyntaxError(InvalidSyntax, self.line, self.col)) + } + } + + fn error_event(&mut self, reason: ErrorCode) -> JsonEvent { + self.state = ParseFinished; + Error(SyntaxError(reason, self.line, self.col)) + } +} + +/// A Builder consumes a json::Parser to create a generic Json structure. +pub struct Builder { + parser: Parser, + token: Option, +} + +impl> Builder { + /// Create a JSON Builder. + pub fn new(src: T) -> Builder { + Builder { parser: Parser::new(src), token: None, } + } + + // Decode a Json value from a Parser. + pub fn build(&mut self) -> Result { + self.bump(); + let result = self.build_value(); + self.bump(); + match self.token { + None => {} + Some(Error(e)) => { return Err(e); } + ref tok => { panic!("unexpected token {}", tok.clone()); } + } + result + } + + fn bump(&mut self) { + self.token = self.parser.next(); + } + + fn build_value(&mut self) -> Result { + return match self.token { + Some(NullValue) => Ok(Json::Null), + Some(I64Value(n)) => Ok(Json::I64(n)), + Some(U64Value(n)) => Ok(Json::U64(n)), + Some(F64Value(n)) => Ok(Json::F64(n)), + Some(BooleanValue(b)) => Ok(Json::Boolean(b)), + Some(StringValue(ref mut s)) => { + let mut temp = string::String::new(); + swap(s, &mut temp); + Ok(Json::String(temp)) + } + Some(Error(e)) => Err(e), + Some(ArrayStart) => self.build_array(), + Some(ObjectStart) => self.build_object(), + Some(ObjectEnd) => self.parser.error(InvalidSyntax), + Some(ArrayEnd) => self.parser.error(InvalidSyntax), + None => self.parser.error(EOFWhileParsingValue), + } + } + + fn build_array(&mut self) -> Result { + self.bump(); + let mut values = Vec::new(); + + loop { + if self.token == Some(ArrayEnd) { + return Ok(Json::Array(values.into_iter().collect())); + } + match self.build_value() { + Ok(v) => values.push(v), + Err(e) => { return Err(e) } + } + self.bump(); + } + } + + fn build_object(&mut self) -> Result { + self.bump(); + + let mut values = BTreeMap::new(); + + loop { + match self.token { + Some(ObjectEnd) => { return Ok(Json::Object(values)); } + Some(Error(e)) => { return Err(e); } + None => { break; } + _ => {} + } + let key = match self.parser.stack().top() { + Some(Key(k)) => { k.to_string() } + _ => { panic!("invalid state"); } + }; + match self.build_value() { + Ok(value) => { values.insert(key, value); } + Err(e) => { return Err(e); } + } + self.bump(); + } + return self.parser.error(EOFWhileParsingObject); + } +} + +/// Decodes a json value from an `&mut io::Reader` +pub fn from_reader(rdr: &mut io::Reader) -> Result { + let contents = match rdr.read_to_end() { + Ok(c) => c, + Err(e) => return Err(io_error_to_error(e)) + }; + let s = match str::from_utf8(contents.as_slice()).ok() { + Some(s) => s, + _ => return Err(SyntaxError(NotUtf8, 0, 0)) + }; + let mut builder = Builder::new(s.chars()); + builder.build() +} + +/// Decodes a json value from a string +pub fn from_str(s: &str) -> Result { + let mut builder = Builder::new(s.chars()); + builder.build() +} + +/// A structure to decode JSON to values in rust. +pub struct Decoder { + stack: Vec, +} + +impl Decoder { + /// Creates a new decoder instance for decoding the specified JSON value. + pub fn new(json: Json) -> Decoder { + Decoder { stack: vec![json] } + } +} + +impl Decoder { + fn pop(&mut self) -> Json { + self.stack.pop().unwrap() + } +} + +macro_rules! expect { + ($e:expr, Null) => ({ + match $e { + Json::Null => Ok(()), + other => Err(ExpectedError("Null".to_string(), + format!("{}", other))) + } + }); + ($e:expr, $t:ident) => ({ + match $e { + Json::$t(v) => Ok(v), + other => { + Err(ExpectedError(stringify!($t).to_string(), + format!("{}", other))) + } + } + }) +} + +macro_rules! read_primitive { + ($name:ident, $ty:ty) => { + fn $name(&mut self) -> DecodeResult<$ty> { + match self.pop() { + Json::I64(f) => match num::cast(f) { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), format!("{}", f))), + }, + Json::U64(f) => match num::cast(f) { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), format!("{}", f))), + }, + Json::F64(f) => Err(ExpectedError("Integer".to_string(), format!("{}", f))), + // re: #12967.. a type w/ numeric keys (ie HashMap etc) + // is going to have a string here, as per JSON spec. + Json::String(s) => match s.parse() { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), s)), + }, + value => Err(ExpectedError("Number".to_string(), format!("{}", value))), + } + } + } +} + +impl ::Decoder for Decoder { + fn read_nil(&mut self) -> DecodeResult<()> { + expect!(self.pop(), Null) + } + + read_primitive! { read_uint, uint } + read_primitive! { read_u8, u8 } + read_primitive! { read_u16, u16 } + read_primitive! { read_u32, u32 } + read_primitive! { read_u64, u64 } + read_primitive! { read_int, int } + read_primitive! { read_i8, i8 } + read_primitive! { read_i16, i16 } + read_primitive! { read_i32, i32 } + read_primitive! { read_i64, i64 } + + fn read_f32(&mut self) -> DecodeResult { self.read_f64().map(|x| x as f32) } + + fn read_f64(&mut self) -> DecodeResult { + match self.pop() { + Json::I64(f) => Ok(f as f64), + Json::U64(f) => Ok(f as f64), + Json::F64(f) => Ok(f), + Json::String(s) => { + // re: #12967.. a type w/ numeric keys (ie HashMap etc) + // is going to have a string here, as per JSON spec. + match s.parse() { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), s)), + } + }, + Json::Null => Ok(f64::NAN), + value => Err(ExpectedError("Number".to_string(), format!("{}", value))) + } + } + + fn read_bool(&mut self) -> DecodeResult { + expect!(self.pop(), Boolean) + } + + fn read_char(&mut self) -> DecodeResult { + let s = try!(self.read_str()); + { + let mut it = s.chars(); + match (it.next(), it.next()) { + // exactly one character + (Some(c), None) => return Ok(c), + _ => () + } + } + Err(ExpectedError("single character string".to_string(), format!("{}", s))) + } + + fn read_str(&mut self) -> DecodeResult { + expect!(self.pop(), String) + } + + fn read_enum(&mut self, _name: &str, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_enum_variant(&mut self, names: &[&str], + mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder, uint) -> DecodeResult, + { + let name = match self.pop() { + Json::String(s) => s, + Json::Object(mut o) => { + let n = match o.remove(&"variant".to_string()) { + Some(Json::String(s)) => s, + Some(val) => { + return Err(ExpectedError("String".to_string(), format!("{}", val))) + } + None => { + return Err(MissingFieldError("variant".to_string())) + } + }; + match o.remove(&"fields".to_string()) { + Some(Json::Array(l)) => { + for field in l.into_iter().rev() { + self.stack.push(field); + } + }, + Some(val) => { + return Err(ExpectedError("Array".to_string(), format!("{}", val))) + } + None => { + return Err(MissingFieldError("fields".to_string())) + } + } + n + } + json => { + return Err(ExpectedError("String or Object".to_string(), format!("{}", json))) + } + }; + let idx = match names.iter().position(|n| *n == name[]) { + Some(idx) => idx, + None => return Err(UnknownVariantError(name)) + }; + f(self, idx) + } + + fn read_enum_variant_arg(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> DecodeResult where + F: FnMut(&mut Decoder, uint) -> DecodeResult, + { + self.read_enum_variant(names, f) + } + + + fn read_enum_struct_variant_field(&mut self, + _name: &str, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_enum_variant_arg(idx, f) + } + + fn read_struct(&mut self, _name: &str, _len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + let value = try!(f(self)); + self.pop(); + Ok(value) + } + + fn read_struct_field(&mut self, + name: &str, + _idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + let mut obj = try!(expect!(self.pop(), Object)); + + let value = match obj.remove(&name.to_string()) { + None => { + // Add a Null and try to parse it as an Option<_> + // to get None as a default value. + self.stack.push(Json::Null); + match f(self) { + Ok(x) => x, + Err(_) => return Err(MissingFieldError(name.to_string())), + } + }, + Some(json) => { + self.stack.push(json); + try!(f(self)) + } + }; + self.stack.push(Json::Object(obj)); + Ok(value) + } + + fn read_tuple(&mut self, tuple_len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_seq(move |d, len| { + if len == tuple_len { + f(d) + } else { + Err(ExpectedError(format!("Tuple{}", tuple_len), format!("Tuple{}", len))) + } + }) + } + + fn read_tuple_arg(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&mut self, + _name: &str, + len: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_tuple(len, f) + } + + fn read_tuple_struct_arg(&mut self, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_tuple_arg(idx, f) + } + + fn read_option(&mut self, mut f: F) -> DecodeResult where + F: FnMut(&mut Decoder, bool) -> DecodeResult, + { + match self.pop() { + Json::Null => f(self, false), + value => { self.stack.push(value); f(self, true) } + } + } + + fn read_seq(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder, uint) -> DecodeResult, + { + let array = try!(expect!(self.pop(), Array)); + let len = array.len(); + for v in array.into_iter().rev() { + self.stack.push(v); + } + f(self, len) + } + + fn read_seq_elt(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_map(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder, uint) -> DecodeResult, + { + let obj = try!(expect!(self.pop(), Object)); + let len = obj.len(); + for (key, value) in obj.into_iter() { + self.stack.push(value); + self.stack.push(Json::String(key)); + } + f(self, len) + } + + fn read_map_elt_key(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_map_elt_val(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn error(&mut self, err: &str) -> DecoderError { + ApplicationError(err.to_string()) + } +} + +/// A trait for converting values to JSON +pub trait ToJson for Sized? { + /// Converts the value of `self` to an instance of JSON + fn to_json(&self) -> Json; +} + +macro_rules! to_json_impl_i64 { + ($($t:ty), +) => ( + $(impl ToJson for $t { + fn to_json(&self) -> Json { Json::I64(*self as i64) } + })+ + ) +} + +to_json_impl_i64! { int, i8, i16, i32, i64 } + +macro_rules! to_json_impl_u64 { + ($($t:ty), +) => ( + $(impl ToJson for $t { + fn to_json(&self) -> Json { Json::U64(*self as u64) } + })+ + ) +} + +to_json_impl_u64! { uint, u8, u16, u32, u64 } + +impl ToJson for Json { + fn to_json(&self) -> Json { self.clone() } +} + +impl ToJson for f32 { + fn to_json(&self) -> Json { (*self as f64).to_json() } +} + +impl ToJson for f64 { + fn to_json(&self) -> Json { + match self.classify() { + Fp::Nan | Fp::Infinite => Json::Null, + _ => Json::F64(*self) + } + } +} + +impl ToJson for () { + fn to_json(&self) -> Json { Json::Null } +} + +impl ToJson for bool { + fn to_json(&self) -> Json { Json::Boolean(*self) } +} + +impl ToJson for str { + fn to_json(&self) -> Json { Json::String(self.to_string()) } +} + +impl ToJson for string::String { + fn to_json(&self) -> Json { Json::String((*self).clone()) } +} + +macro_rules! tuple_impl { + // use variables to indicate the arity of the tuple + ($($tyvar:ident),* ) => { + // the trailing commas are for the 1 tuple + impl< + $( $tyvar : ToJson ),* + > ToJson for ( $( $tyvar ),* , ) { + + #[inline] + #[allow(non_snake_case)] + fn to_json(&self) -> Json { + match *self { + ($(ref $tyvar),*,) => Json::Array(vec![$($tyvar.to_json()),*]) + } + } + } + } +} + +tuple_impl!{A} +tuple_impl!{A, B} +tuple_impl!{A, B, C} +tuple_impl!{A, B, C, D} +tuple_impl!{A, B, C, D, E} +tuple_impl!{A, B, C, D, E, F} +tuple_impl!{A, B, C, D, E, F, G} +tuple_impl!{A, B, C, D, E, F, G, H} +tuple_impl!{A, B, C, D, E, F, G, H, I} +tuple_impl!{A, B, C, D, E, F, G, H, I, J} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L} + +impl ToJson for [A] { + fn to_json(&self) -> Json { Json::Array(self.iter().map(|elt| elt.to_json()).collect()) } +} + +impl ToJson for Vec { + fn to_json(&self) -> Json { Json::Array(self.iter().map(|elt| elt.to_json()).collect()) } +} + +impl ToJson for BTreeMap { + fn to_json(&self) -> Json { + let mut d = BTreeMap::new(); + for (key, value) in self.iter() { + d.insert((*key).clone(), value.to_json()); + } + Json::Object(d) + } +} + +impl ToJson for HashMap { + fn to_json(&self) -> Json { + let mut d = BTreeMap::new(); + for (key, value) in self.iter() { + d.insert((*key).clone(), value.to_json()); + } + Json::Object(d) + } +} + +impl ToJson for Option { + fn to_json(&self) -> Json { + match *self { + None => Json::Null, + Some(ref value) => value.to_json() + } + } +} + +struct FormatShim<'a, 'b: 'a> { + inner: &'a mut fmt::Formatter<'b>, +} + +impl<'a, 'b> fmt::Writer for FormatShim<'a, 'b> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.inner.write_str(s) + } +} + +impl fmt::Show for Json { + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = Encoder::new(&mut shim); + self.encode(&mut encoder) + } +} + +impl<'a> fmt::Show for PrettyJson<'a> { + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = PrettyEncoder::new(&mut shim); + self.inner.encode(&mut encoder) + } +} + +impl<'a, T> fmt::Show for AsJson<'a, T> + where T: for<'b> Encodable, fmt::Error> +{ + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = Encoder::new(&mut shim); + self.inner.encode(&mut encoder) + } +} + +impl<'a, T> AsPrettyJson<'a, T> { + /// Set the indentation level for the emitted JSON + pub fn indent(mut self, indent: uint) -> AsPrettyJson<'a, T> { + self.indent = Some(indent); + self + } +} + +impl<'a, T> fmt::Show for AsPrettyJson<'a, T> + where T: for<'b> Encodable, fmt::Error> +{ + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = PrettyEncoder::new(&mut shim); + match self.indent { + Some(n) => encoder.set_indent(n), + None => {} + } + self.inner.encode(&mut encoder) + } +} + +impl FromStr for Json { + fn from_str(s: &str) -> Option { + from_str(s).ok() + } +} + +#[cfg(test)] +mod tests { + extern crate test; + use self::Animal::*; + use self::DecodeEnum::*; + use self::test::Bencher; + use {Encodable, Decodable}; + use super::Json::*; + use super::ErrorCode::*; + use super::ParserError::*; + use super::DecoderError::*; + use super::JsonEvent::*; + use super::StackElement::*; + use super::{Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser, + StackElement, Stack, Decoder}; + use std::{i64, u64, f32, f64}; + use std::collections::BTreeMap; + use std::num::Float; + use std::string; + + #[derive(RustcDecodable, Eq, PartialEq, Show)] + struct OptionData { + opt: Option, + } + + #[test] + fn test_decode_option_none() { + let s ="{}"; + let obj: OptionData = super::decode(s).unwrap(); + assert_eq!(obj, OptionData { opt: None }); + } + + #[test] + fn test_decode_option_some() { + let s = "{ \"opt\": 10 }"; + let obj: OptionData = super::decode(s).unwrap(); + assert_eq!(obj, OptionData { opt: Some(10u) }); + } + + #[test] + fn test_decode_option_malformed() { + check_err::("{ \"opt\": [] }", + ExpectedError("Number".to_string(), "[]".to_string())); + check_err::("{ \"opt\": false }", + ExpectedError("Number".to_string(), "false".to_string())); + } + + #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)] + enum Animal { + Dog, + Frog(string::String, int) + } + + #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)] + struct Inner { + a: (), + b: uint, + c: Vec, + } + + #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)] + struct Outer { + inner: Vec, + } + + fn mk_object(items: &[(string::String, Json)]) -> Json { + let mut d = BTreeMap::new(); + + for item in items.iter() { + match *item { + (ref key, ref value) => { d.insert((*key).clone(), (*value).clone()); }, + } + }; + + Object(d) + } + + #[test] + fn test_from_str_trait() { + let s = "null"; + assert!(s.parse::().unwrap() == s.parse().unwrap()); + } + + #[test] + fn test_write_null() { + assert_eq!(Null.to_string(), "null"); + assert_eq!(Null.pretty().to_string(), "null"); + } + + #[test] + fn test_write_i64() { + assert_eq!(U64(0).to_string(), "0"); + assert_eq!(U64(0).pretty().to_string(), "0"); + + assert_eq!(U64(1234).to_string(), "1234"); + assert_eq!(U64(1234).pretty().to_string(), "1234"); + + assert_eq!(I64(-5678).to_string(), "-5678"); + assert_eq!(I64(-5678).pretty().to_string(), "-5678"); + + assert_eq!(U64(7650007200025252000).to_string(), "7650007200025252000"); + assert_eq!(U64(7650007200025252000).pretty().to_string(), "7650007200025252000"); + } + + #[test] + fn test_write_f64() { + assert_eq!(F64(3.0).to_string(), "3.0"); + assert_eq!(F64(3.0).pretty().to_string(), "3.0"); + + assert_eq!(F64(3.1).to_string(), "3.1"); + assert_eq!(F64(3.1).pretty().to_string(), "3.1"); + + assert_eq!(F64(-1.5).to_string(), "-1.5"); + assert_eq!(F64(-1.5).pretty().to_string(), "-1.5"); + + assert_eq!(F64(0.5).to_string(), "0.5"); + assert_eq!(F64(0.5).pretty().to_string(), "0.5"); + + assert_eq!(F64(f64::NAN).to_string(), "null"); + assert_eq!(F64(f64::NAN).pretty().to_string(), "null"); + + assert_eq!(F64(f64::INFINITY).to_string(), "null"); + assert_eq!(F64(f64::INFINITY).pretty().to_string(), "null"); + + assert_eq!(F64(f64::NEG_INFINITY).to_string(), "null"); + assert_eq!(F64(f64::NEG_INFINITY).pretty().to_string(), "null"); + } + + #[test] + fn test_write_str() { + assert_eq!(String("".to_string()).to_string(), "\"\""); + assert_eq!(String("".to_string()).pretty().to_string(), "\"\""); + + assert_eq!(String("homura".to_string()).to_string(), "\"homura\""); + assert_eq!(String("madoka".to_string()).pretty().to_string(), "\"madoka\""); + } + + #[test] + fn test_write_bool() { + assert_eq!(Boolean(true).to_string(), "true"); + assert_eq!(Boolean(true).pretty().to_string(), "true"); + + assert_eq!(Boolean(false).to_string(), "false"); + assert_eq!(Boolean(false).pretty().to_string(), "false"); + } + + #[test] + fn test_write_array() { + assert_eq!(Array(vec![]).to_string(), "[]"); + assert_eq!(Array(vec![]).pretty().to_string(), "[]"); + + assert_eq!(Array(vec![Boolean(true)]).to_string(), "[true]"); + assert_eq!( + Array(vec![Boolean(true)]).pretty().to_string(), + "\ + [\n \ + true\n\ + ]" + ); + + let long_test_array = Array(vec![ + Boolean(false), + Null, + Array(vec![String("foo\nbar".to_string()), F64(3.5)])]); + + assert_eq!(long_test_array.to_string(), + "[false,null,[\"foo\\nbar\",3.5]]"); + assert_eq!( + long_test_array.pretty().to_string(), + "\ + [\n \ + false,\n \ + null,\n \ + [\n \ + \"foo\\nbar\",\n \ + 3.5\n \ + ]\n\ + ]" + ); + } + + #[test] + fn test_write_object() { + assert_eq!(mk_object(&[]).to_string(), "{}"); + assert_eq!(mk_object(&[]).pretty().to_string(), "{}"); + + assert_eq!( + mk_object(&[ + ("a".to_string(), Boolean(true)) + ]).to_string(), + "{\"a\":true}" + ); + assert_eq!( + mk_object(&[("a".to_string(), Boolean(true))]).pretty().to_string(), + "\ + {\n \ + \"a\": true\n\ + }" + ); + + let complex_obj = mk_object(&[ + ("b".to_string(), Array(vec![ + mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]), + mk_object(&[("d".to_string(), String("".to_string()))]) + ])) + ]); + + assert_eq!( + complex_obj.to_string(), + "{\ + \"b\":[\ + {\"c\":\"\\f\\r\"},\ + {\"d\":\"\"}\ + ]\ + }" + ); + assert_eq!( + complex_obj.pretty().to_string(), + "\ + {\n \ + \"b\": [\n \ + {\n \ + \"c\": \"\\f\\r\"\n \ + },\n \ + {\n \ + \"d\": \"\"\n \ + }\n \ + ]\n\ + }" + ); + + let a = mk_object(&[ + ("a".to_string(), Boolean(true)), + ("b".to_string(), Array(vec![ + mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]), + mk_object(&[("d".to_string(), String("".to_string()))]) + ])) + ]); + + // We can't compare the strings directly because the object fields be + // printed in a different order. + assert_eq!(a.clone(), a.to_string().parse().unwrap()); + assert_eq!(a.clone(), a.pretty().to_string().parse().unwrap()); + } + + #[test] + fn test_write_enum() { + let animal = Dog; + assert_eq!( + format!("{}", super::as_json(&animal)), + "\"Dog\"" + ); + assert_eq!( + format!("{}", super::as_pretty_json(&animal)), + "\"Dog\"" + ); + + let animal = Frog("Henry".to_string(), 349); + assert_eq!( + format!("{}", super::as_json(&animal)), + "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}" + ); + assert_eq!( + format!("{}", super::as_pretty_json(&animal)), + "{\n \ + \"variant\": \"Frog\",\n \ + \"fields\": [\n \ + \"Henry\",\n \ + 349\n \ + ]\n\ + }" + ); + } + + macro_rules! check_encoder_for_simple { + ($value:expr, $expected:expr) => ({ + let s = format!("{}", super::as_json(&$value)); + assert_eq!(s, $expected); + + let s = format!("{}", super::as_pretty_json(&$value)); + assert_eq!(s, $expected); + }) + } + + #[test] + fn test_write_some() { + check_encoder_for_simple!(Some("jodhpurs".to_string()), "\"jodhpurs\""); + } + + #[test] + fn test_write_none() { + check_encoder_for_simple!(None::, "null"); + } + + #[test] + fn test_write_char() { + check_encoder_for_simple!('a', "\"a\""); + check_encoder_for_simple!('\t', "\"\\t\""); + check_encoder_for_simple!('\u{0000}', "\"\\u0000\""); + check_encoder_for_simple!('\u{001b}', "\"\\u001b\""); + check_encoder_for_simple!('\u{007f}', "\"\\u007f\""); + check_encoder_for_simple!('\u{00a0}', "\"\u{00a0}\""); + check_encoder_for_simple!('\u{abcd}', "\"\u{abcd}\""); + check_encoder_for_simple!('\u{10ffff}', "\"\u{10ffff}\""); + } + + #[test] + fn test_trailing_characters() { + assert_eq!(from_str("nulla"), Err(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(from_str("truea"), Err(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(from_str("falsea"), Err(SyntaxError(TrailingCharacters, 1, 6))); + assert_eq!(from_str("1a"), Err(SyntaxError(TrailingCharacters, 1, 2))); + assert_eq!(from_str("[]a"), Err(SyntaxError(TrailingCharacters, 1, 3))); + assert_eq!(from_str("{}a"), Err(SyntaxError(TrailingCharacters, 1, 3))); + } + + #[test] + fn test_read_identifiers() { + assert_eq!(from_str("n"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(from_str("nul"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("t"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(from_str("truz"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("f"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(from_str("faz"), Err(SyntaxError(InvalidSyntax, 1, 3))); + + assert_eq!(from_str("null"), Ok(Null)); + assert_eq!(from_str("true"), Ok(Boolean(true))); + assert_eq!(from_str("false"), Ok(Boolean(false))); + assert_eq!(from_str(" null "), Ok(Null)); + assert_eq!(from_str(" true "), Ok(Boolean(true))); + assert_eq!(from_str(" false "), Ok(Boolean(false))); + } + + #[test] + fn test_decode_identifiers() { + let v: () = super::decode("null").unwrap(); + assert_eq!(v, ()); + + let v: bool = super::decode("true").unwrap(); + assert_eq!(v, true); + + let v: bool = super::decode("false").unwrap(); + assert_eq!(v, false); + } + + #[test] + fn test_read_number() { + assert_eq!(from_str("+"), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(from_str("."), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(from_str("NaN"), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(from_str("-"), Err(SyntaxError(InvalidNumber, 1, 2))); + assert_eq!(from_str("00"), Err(SyntaxError(InvalidNumber, 1, 2))); + assert_eq!(from_str("1."), Err(SyntaxError(InvalidNumber, 1, 3))); + assert_eq!(from_str("1e"), Err(SyntaxError(InvalidNumber, 1, 3))); + assert_eq!(from_str("1e+"), Err(SyntaxError(InvalidNumber, 1, 4))); + + assert_eq!(from_str("18446744073709551616"), Err(SyntaxError(InvalidNumber, 1, 20))); + assert_eq!(from_str("-9223372036854775809"), Err(SyntaxError(InvalidNumber, 1, 21))); + + assert_eq!(from_str("3"), Ok(U64(3))); + assert_eq!(from_str("3.1"), Ok(F64(3.1))); + assert_eq!(from_str("-1.2"), Ok(F64(-1.2))); + assert_eq!(from_str("0.4"), Ok(F64(0.4))); + assert_eq!(from_str("0.4e5"), Ok(F64(0.4e5))); + assert_eq!(from_str("0.4e+15"), Ok(F64(0.4e15))); + assert_eq!(from_str("0.4e-01"), Ok(F64(0.4e-01))); + assert_eq!(from_str(" 3 "), Ok(U64(3))); + + assert_eq!(from_str("-9223372036854775808"), Ok(I64(i64::MIN))); + assert_eq!(from_str("9223372036854775807"), Ok(U64(i64::MAX as u64))); + assert_eq!(from_str("18446744073709551615"), Ok(U64(u64::MAX))); + } + + #[test] + fn test_decode_numbers() { + let v: f64 = super::decode("3").unwrap(); + assert_eq!(v, 3.0); + + let v: f64 = super::decode("3.1").unwrap(); + assert_eq!(v, 3.1); + + let v: f64 = super::decode("-1.2").unwrap(); + assert_eq!(v, -1.2); + + let v: f64 = super::decode("0.4").unwrap(); + assert_eq!(v, 0.4); + + let v: f64 = super::decode("0.4e5").unwrap(); + assert_eq!(v, 0.4e5); + + let v: f64 = super::decode("0.4e15").unwrap(); + assert_eq!(v, 0.4e15); + + let v: f64 = super::decode("0.4e-01").unwrap(); + assert_eq!(v, 0.4e-01); + + let v: u64 = super::decode("0").unwrap(); + assert_eq!(v, 0); + + let v: u64 = super::decode("18446744073709551615").unwrap(); + assert_eq!(v, u64::MAX); + + let v: i64 = super::decode("-9223372036854775808").unwrap(); + assert_eq!(v, i64::MIN); + + let v: i64 = super::decode("9223372036854775807").unwrap(); + assert_eq!(v, i64::MAX); + + let res: DecodeResult = super::decode("765.25252"); + assert_eq!(res, Err(ExpectedError("Integer".to_string(), "765.25252".to_string()))); + } + + #[test] + fn test_read_str() { + assert_eq!(from_str("\""), Err(SyntaxError(EOFWhileParsingString, 1, 2))); + assert_eq!(from_str("\"lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5))); + + assert_eq!(from_str("\"\""), Ok(String("".to_string()))); + assert_eq!(from_str("\"foo\""), Ok(String("foo".to_string()))); + assert_eq!(from_str("\"\\\"\""), Ok(String("\"".to_string()))); + assert_eq!(from_str("\"\\b\""), Ok(String("\x08".to_string()))); + assert_eq!(from_str("\"\\n\""), Ok(String("\n".to_string()))); + assert_eq!(from_str("\"\\r\""), Ok(String("\r".to_string()))); + assert_eq!(from_str("\"\\t\""), Ok(String("\t".to_string()))); + assert_eq!(from_str(" \"foo\" "), Ok(String("foo".to_string()))); + assert_eq!(from_str("\"\\u12ab\""), Ok(String("\u{12ab}".to_string()))); + assert_eq!(from_str("\"\\uAB12\""), Ok(String("\u{AB12}".to_string()))); + } + + #[test] + fn test_decode_str() { + let s = [("\"\"", ""), + ("\"foo\"", "foo"), + ("\"\\\"\"", "\""), + ("\"\\b\"", "\x08"), + ("\"\\n\"", "\n"), + ("\"\\r\"", "\r"), + ("\"\\t\"", "\t"), + ("\"\\u12ab\"", "\u{12ab}"), + ("\"\\uAB12\"", "\u{AB12}")]; + + for &(i, o) in s.iter() { + let v: string::String = super::decode(i).unwrap(); + assert_eq!(v, o); + } + } + + #[test] + fn test_read_array() { + assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2))); + assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3))); + assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4))); + assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + + assert_eq!(from_str("[]"), Ok(Array(vec![]))); + assert_eq!(from_str("[ ]"), Ok(Array(vec![]))); + assert_eq!(from_str("[true]"), Ok(Array(vec![Boolean(true)]))); + assert_eq!(from_str("[ false ]"), Ok(Array(vec![Boolean(false)]))); + assert_eq!(from_str("[null]"), Ok(Array(vec![Null]))); + assert_eq!(from_str("[3, 1]"), + Ok(Array(vec![U64(3), U64(1)]))); + assert_eq!(from_str("\n[3, 2]\n"), + Ok(Array(vec![U64(3), U64(2)]))); + assert_eq!(from_str("[2, [4, 1]]"), + Ok(Array(vec![U64(2), Array(vec![U64(4), U64(1)])]))); + } + + #[test] + fn test_decode_array() { + let v: Vec<()> = super::decode("[]").unwrap(); + assert_eq!(v, vec![]); + + let v: Vec<()> = super::decode("[null]").unwrap(); + assert_eq!(v, vec![()]); + + let v: Vec = super::decode("[true]").unwrap(); + assert_eq!(v, vec![true]); + + let v: Vec = super::decode("[3, 1]").unwrap(); + assert_eq!(v, vec![3, 1]); + + let v: Vec> = super::decode("[[3], [1, 2]]").unwrap(); + assert_eq!(v, vec![vec![3], vec![1, 2]]); + } + + #[test] + fn test_decode_tuple() { + let t: (uint, uint, uint) = super::decode("[1, 2, 3]").unwrap(); + assert_eq!(t, (1u, 2, 3)); + + let t: (uint, string::String) = super::decode("[1, \"two\"]").unwrap(); + assert_eq!(t, (1u, "two".to_string())); + } + + #[test] + fn test_decode_tuple_malformed_types() { + assert!(super::decode::<(uint, string::String)>("[1, 2]").is_err()); + } + + #[test] + fn test_decode_tuple_malformed_length() { + assert!(super::decode::<(uint, uint)>("[1, 2, 3]").is_err()); + } + + #[test] + fn test_read_object() { + assert_eq!(from_str("{"), Err(SyntaxError(EOFWhileParsingObject, 1, 2))); + assert_eq!(from_str("{ "), Err(SyntaxError(EOFWhileParsingObject, 1, 3))); + assert_eq!(from_str("{1"), Err(SyntaxError(KeyMustBeAString, 1, 2))); + assert_eq!(from_str("{ \"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 6))); + assert_eq!(from_str("{\"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 5))); + assert_eq!(from_str("{\"a\" "), Err(SyntaxError(EOFWhileParsingObject, 1, 6))); + + assert_eq!(from_str("{\"a\" 1"), Err(SyntaxError(ExpectedColon, 1, 6))); + assert_eq!(from_str("{\"a\":"), Err(SyntaxError(EOFWhileParsingValue, 1, 6))); + assert_eq!(from_str("{\"a\":1"), Err(SyntaxError(EOFWhileParsingObject, 1, 7))); + assert_eq!(from_str("{\"a\":1 1"), Err(SyntaxError(InvalidSyntax, 1, 8))); + assert_eq!(from_str("{\"a\":1,"), Err(SyntaxError(EOFWhileParsingObject, 1, 8))); + + assert_eq!(from_str("{}").unwrap(), mk_object(&[])); + assert_eq!(from_str("{\"a\": 3}").unwrap(), + mk_object(&[("a".to_string(), U64(3))])); + + assert_eq!(from_str( + "{ \"a\": null, \"b\" : true }").unwrap(), + mk_object(&[ + ("a".to_string(), Null), + ("b".to_string(), Boolean(true))])); + assert_eq!(from_str("\n{ \"a\": null, \"b\" : true }\n").unwrap(), + mk_object(&[ + ("a".to_string(), Null), + ("b".to_string(), Boolean(true))])); + assert_eq!(from_str( + "{\"a\" : 1.0 ,\"b\": [ true ]}").unwrap(), + mk_object(&[ + ("a".to_string(), F64(1.0)), + ("b".to_string(), Array(vec![Boolean(true)])) + ])); + assert_eq!(from_str( + "{\ + \"a\": 1.0, \ + \"b\": [\ + true,\ + \"foo\\nbar\", \ + { \"c\": {\"d\": null} } \ + ]\ + }").unwrap(), + mk_object(&[ + ("a".to_string(), F64(1.0)), + ("b".to_string(), Array(vec![ + Boolean(true), + String("foo\nbar".to_string()), + mk_object(&[ + ("c".to_string(), mk_object(&[("d".to_string(), Null)])) + ]) + ])) + ])); + } + + #[test] + fn test_decode_struct() { + let s = "{ + \"inner\": [ + { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] } + ] + }"; + + let v: Outer = super::decode(s).unwrap(); + assert_eq!( + v, + Outer { + inner: vec![ + Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] } + ] + } + ); + } + + #[derive(RustcDecodable)] + struct FloatStruct { + f: f64, + a: Vec + } + #[test] + fn test_decode_struct_with_nan() { + let s = "{\"f\":null,\"a\":[null,123]}"; + let obj: FloatStruct = super::decode(s).unwrap(); + assert!(obj.f.is_nan()); + assert!(obj.a[0].is_nan()); + assert_eq!(obj.a[1], 123f64); + } + + #[test] + fn test_decode_option() { + let value: Option = super::decode("null").unwrap(); + assert_eq!(value, None); + + let value: Option = super::decode("\"jodhpurs\"").unwrap(); + assert_eq!(value, Some("jodhpurs".to_string())); + } + + #[test] + fn test_decode_enum() { + let value: Animal = super::decode("\"Dog\"").unwrap(); + assert_eq!(value, Dog); + + let s = "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"; + let value: Animal = super::decode(s).unwrap(); + assert_eq!(value, Frog("Henry".to_string(), 349)); + } + + #[test] + fn test_decode_map() { + let s = "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\ + \"fields\":[\"Henry\", 349]}}"; + let mut map: BTreeMap = super::decode(s).unwrap(); + + assert_eq!(map.remove(&"a".to_string()), Some(Dog)); + assert_eq!(map.remove(&"b".to_string()), Some(Frog("Henry".to_string(), 349))); + } + + #[test] + fn test_multiline_errors() { + assert_eq!(from_str("{\n \"foo\":\n \"bar\""), + Err(SyntaxError(EOFWhileParsingObject, 3u, 8u))); + } + + #[derive(RustcDecodable)] + #[allow(dead_code)] + struct DecodeStruct { + x: f64, + y: bool, + z: string::String, + w: Vec + } + #[derive(RustcDecodable)] + enum DecodeEnum { + A(f64), + B(string::String) + } + fn check_err>(to_parse: &'static str, + expected: DecoderError) { + let res: DecodeResult = match from_str(to_parse) { + Err(e) => Err(ParseError(e)), + Ok(json) => Decodable::decode(&mut Decoder::new(json)) + }; + match res { + Ok(_) => panic!("`{}` parsed & decoded ok, expecting error `{}`", + to_parse, expected), + Err(ParseError(e)) => panic!("`{}` is not valid json: {}", + to_parse, e), + Err(e) => { + assert_eq!(e, expected); + } + } + } + #[test] + fn test_decode_errors_struct() { + check_err::("[]", ExpectedError("Object".to_string(), "[]".to_string())); + check_err::("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}", + ExpectedError("Number".to_string(), "true".to_string())); + check_err::("{\"x\": 1, \"y\": [], \"z\": \"\", \"w\": []}", + ExpectedError("Boolean".to_string(), "[]".to_string())); + check_err::("{\"x\": 1, \"y\": true, \"z\": {}, \"w\": []}", + ExpectedError("String".to_string(), "{}".to_string())); + check_err::("{\"x\": 1, \"y\": true, \"z\": \"\", \"w\": null}", + ExpectedError("Array".to_string(), "null".to_string())); + check_err::("{\"x\": 1, \"y\": true, \"z\": \"\"}", + MissingFieldError("w".to_string())); + } + #[test] + fn test_decode_errors_enum() { + check_err::("{}", + MissingFieldError("variant".to_string())); + check_err::("{\"variant\": 1}", + ExpectedError("String".to_string(), "1".to_string())); + check_err::("{\"variant\": \"A\"}", + MissingFieldError("fields".to_string())); + check_err::("{\"variant\": \"A\", \"fields\": null}", + ExpectedError("Array".to_string(), "null".to_string())); + check_err::("{\"variant\": \"C\", \"fields\": []}", + UnknownVariantError("C".to_string())); + } + + #[test] + fn test_find(){ + let json_value = from_str("{\"dog\" : \"cat\"}").unwrap(); + let found_str = json_value.find("dog"); + assert!(found_str.unwrap().as_string().unwrap() == "cat"); + } + + #[test] + fn test_find_path(){ + let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap(); + let found_str = json_value.find_path(&["dog", "cat", "mouse"]); + assert!(found_str.unwrap().as_string().unwrap() == "cheese"); + } + + #[test] + fn test_search(){ + let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap(); + let found_str = json_value.search("mouse").and_then(|j| j.as_string()); + assert!(found_str.unwrap() == "cheese"); + } + + #[test] + fn test_index(){ + let json_value = from_str("{\"animals\":[\"dog\",\"cat\",\"mouse\"]}").unwrap(); + let ref array = json_value["animals"]; + assert_eq!(array[0].as_string().unwrap(), "dog"); + assert_eq!(array[1].as_string().unwrap(), "cat"); + assert_eq!(array[2].as_string().unwrap(), "mouse"); + } + + #[test] + fn test_is_object(){ + let json_value = from_str("{}").unwrap(); + assert!(json_value.is_object()); + } + + #[test] + fn test_as_object(){ + let json_value = from_str("{}").unwrap(); + let json_object = json_value.as_object(); + assert!(json_object.is_some()); + } + + #[test] + fn test_is_array(){ + let json_value = from_str("[1, 2, 3]").unwrap(); + assert!(json_value.is_array()); + } + + #[test] + fn test_as_array(){ + let json_value = from_str("[1, 2, 3]").unwrap(); + let json_array = json_value.as_array(); + let expected_length = 3; + assert!(json_array.is_some() && json_array.unwrap().len() == expected_length); + } + + #[test] + fn test_is_string(){ + let json_value = from_str("\"dog\"").unwrap(); + assert!(json_value.is_string()); + } + + #[test] + fn test_as_string(){ + let json_value = from_str("\"dog\"").unwrap(); + let json_str = json_value.as_string(); + let expected_str = "dog"; + assert_eq!(json_str, Some(expected_str)); + } + + #[test] + fn test_is_number(){ + let json_value = from_str("12").unwrap(); + assert!(json_value.is_number()); + } + + #[test] + fn test_is_i64(){ + let json_value = from_str("-12").unwrap(); + assert!(json_value.is_i64()); + + let json_value = from_str("12").unwrap(); + assert!(!json_value.is_i64()); + + let json_value = from_str("12.0").unwrap(); + assert!(!json_value.is_i64()); + } + + #[test] + fn test_is_u64(){ + let json_value = from_str("12").unwrap(); + assert!(json_value.is_u64()); + + let json_value = from_str("-12").unwrap(); + assert!(!json_value.is_u64()); + + let json_value = from_str("12.0").unwrap(); + assert!(!json_value.is_u64()); + } + + #[test] + fn test_is_f64(){ + let json_value = from_str("12").unwrap(); + assert!(!json_value.is_f64()); + + let json_value = from_str("-12").unwrap(); + assert!(!json_value.is_f64()); + + let json_value = from_str("12.0").unwrap(); + assert!(json_value.is_f64()); + + let json_value = from_str("-12.0").unwrap(); + assert!(json_value.is_f64()); + } + + #[test] + fn test_as_i64(){ + let json_value = from_str("-12").unwrap(); + let json_num = json_value.as_i64(); + assert_eq!(json_num, Some(-12)); + } + + #[test] + fn test_as_u64(){ + let json_value = from_str("12").unwrap(); + let json_num = json_value.as_u64(); + assert_eq!(json_num, Some(12)); + } + + #[test] + fn test_as_f64(){ + let json_value = from_str("12.0").unwrap(); + let json_num = json_value.as_f64(); + assert_eq!(json_num, Some(12f64)); + } + + #[test] + fn test_is_boolean(){ + let json_value = from_str("false").unwrap(); + assert!(json_value.is_boolean()); + } + + #[test] + fn test_as_boolean(){ + let json_value = from_str("false").unwrap(); + let json_bool = json_value.as_boolean(); + let expected_bool = false; + assert!(json_bool.is_some() && json_bool.unwrap() == expected_bool); + } + + #[test] + fn test_is_null(){ + let json_value = from_str("null").unwrap(); + assert!(json_value.is_null()); + } + + #[test] + fn test_as_null(){ + let json_value = from_str("null").unwrap(); + let json_null = json_value.as_null(); + let expected_null = (); + assert!(json_null.is_some() && json_null.unwrap() == expected_null); + } + + #[test] + fn test_encode_hashmap_with_numeric_key() { + use std::str::from_utf8; + use std::io::Writer; + use std::collections::HashMap; + let mut hm: HashMap = HashMap::new(); + hm.insert(1, true); + let mut mem_buf = Vec::new(); + write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap(); + let json_str = from_utf8(mem_buf[]).unwrap(); + match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + _ => {} // it parsed and we are good to go + } + } + + #[test] + fn test_prettyencode_hashmap_with_numeric_key() { + use std::str::from_utf8; + use std::io::Writer; + use std::collections::HashMap; + let mut hm: HashMap = HashMap::new(); + hm.insert(1, true); + let mut mem_buf = Vec::new(); + write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap(); + let json_str = from_utf8(mem_buf[]).unwrap(); + match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + _ => {} // it parsed and we are good to go + } + } + + #[test] + fn test_prettyencoder_indent_level_param() { + use std::str::from_utf8; + use std::collections::BTreeMap; + + let mut tree = BTreeMap::new(); + + tree.insert("hello".to_string(), String("guten tag".to_string())); + tree.insert("goodbye".to_string(), String("sayonara".to_string())); + + let json = Array( + // The following layout below should look a lot like + // the pretty-printed JSON (indent * x) + vec! + ( // 0x + String("greetings".to_string()), // 1x + Object(tree), // 1x + 2x + 2x + 1x + ) // 0x + // End JSON array (7 lines) + ); + + // Helper function for counting indents + fn indents(source: &str) -> uint { + let trimmed = source.trim_left_matches(' '); + source.len() - trimmed.len() + } + + // Test up to 4 spaces of indents (more?) + for i in range(0, 4u) { + let mut writer = Vec::new(); + write!(&mut writer, "{}", + super::as_pretty_json(&json).indent(i)).unwrap(); + + let printed = from_utf8(writer[]).unwrap(); + + // Check for indents at each line + let lines: Vec<&str> = printed.lines().collect(); + assert_eq!(lines.len(), 7); // JSON should be 7 lines + + assert_eq!(indents(lines[0]), 0 * i); // [ + assert_eq!(indents(lines[1]), 1 * i); // "greetings", + assert_eq!(indents(lines[2]), 1 * i); // { + assert_eq!(indents(lines[3]), 2 * i); // "hello": "guten tag", + assert_eq!(indents(lines[4]), 2 * i); // "goodbye": "sayonara" + assert_eq!(indents(lines[5]), 1 * i); // }, + assert_eq!(indents(lines[6]), 0 * i); // ] + + // Finally, test that the pretty-printed JSON is valid + from_str(printed).ok().expect("Pretty-printed JSON is invalid!"); + } + } + + #[test] + fn test_hashmap_with_numeric_key_can_handle_double_quote_delimited_key() { + use std::collections::HashMap; + use Decodable; + let json_str = "{\"1\":true}"; + let json_obj = match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + Ok(o) => o + }; + let mut decoder = Decoder::new(json_obj); + let _hm: HashMap = Decodable::decode(&mut decoder).unwrap(); + } + + #[test] + fn test_hashmap_with_numeric_key_will_error_with_string_keys() { + use std::collections::HashMap; + use Decodable; + let json_str = "{\"a\":true}"; + let json_obj = match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + Ok(o) => o + }; + let mut decoder = Decoder::new(json_obj); + let result: Result, DecoderError> = Decodable::decode(&mut decoder); + assert_eq!(result, Err(ExpectedError("Number".to_string(), "a".to_string()))); + } + + fn assert_stream_equal(src: &str, + expected: Vec<(JsonEvent, Vec)>) { + let mut parser = Parser::new(src.chars()); + let mut i = 0; + loop { + let evt = match parser.next() { + Some(e) => e, + None => { break; } + }; + let (ref expected_evt, ref expected_stack) = expected[i]; + if !parser.stack().is_equal_to(expected_stack.as_slice()) { + panic!("Parser stack is not equal to {}", expected_stack); + } + assert_eq!(&evt, expected_evt); + i+=1; + } + } + #[test] + #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + fn test_streaming_parser() { + assert_stream_equal( + r#"{ "foo":"bar", "array" : [0, 1, 2, 3, 4, 5], "idents":[null,true,false]}"#, + vec![ + (ObjectStart, vec![]), + (StringValue("bar".to_string()), vec![Key("foo")]), + (ArrayStart, vec![Key("array")]), + (U64Value(0), vec![Key("array"), Index(0)]), + (U64Value(1), vec![Key("array"), Index(1)]), + (U64Value(2), vec![Key("array"), Index(2)]), + (U64Value(3), vec![Key("array"), Index(3)]), + (U64Value(4), vec![Key("array"), Index(4)]), + (U64Value(5), vec![Key("array"), Index(5)]), + (ArrayEnd, vec![Key("array")]), + (ArrayStart, vec![Key("idents")]), + (NullValue, vec![Key("idents"), Index(0)]), + (BooleanValue(true), vec![Key("idents"), Index(1)]), + (BooleanValue(false), vec![Key("idents"), Index(2)]), + (ArrayEnd, vec![Key("idents")]), + (ObjectEnd, vec![]), + ] + ); + } + fn last_event(src: &str) -> JsonEvent { + let mut parser = Parser::new(src.chars()); + let mut evt = NullValue; + loop { + evt = match parser.next() { + Some(e) => e, + None => return evt, + } + } + } + + #[test] + #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + fn test_read_object_streaming() { + assert_eq!(last_event("{ "), Error(SyntaxError(EOFWhileParsingObject, 1, 3))); + assert_eq!(last_event("{1"), Error(SyntaxError(KeyMustBeAString, 1, 2))); + assert_eq!(last_event("{ \"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 6))); + assert_eq!(last_event("{\"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 5))); + assert_eq!(last_event("{\"a\" "), Error(SyntaxError(EOFWhileParsingObject, 1, 6))); + + assert_eq!(last_event("{\"a\" 1"), Error(SyntaxError(ExpectedColon, 1, 6))); + assert_eq!(last_event("{\"a\":"), Error(SyntaxError(EOFWhileParsingValue, 1, 6))); + assert_eq!(last_event("{\"a\":1"), Error(SyntaxError(EOFWhileParsingObject, 1, 7))); + assert_eq!(last_event("{\"a\":1 1"), Error(SyntaxError(InvalidSyntax, 1, 8))); + assert_eq!(last_event("{\"a\":1,"), Error(SyntaxError(EOFWhileParsingObject, 1, 8))); + assert_eq!(last_event("{\"a\":1,}"), Error(SyntaxError(TrailingComma, 1, 8))); + + assert_stream_equal( + "{}", + vec![(ObjectStart, vec![]), (ObjectEnd, vec![])] + ); + assert_stream_equal( + "{\"a\": 3}", + vec![ + (ObjectStart, vec![]), + (U64Value(3), vec![Key("a")]), + (ObjectEnd, vec![]), + ] + ); + assert_stream_equal( + "{ \"a\": null, \"b\" : true }", + vec![ + (ObjectStart, vec![]), + (NullValue, vec![Key("a")]), + (BooleanValue(true), vec![Key("b")]), + (ObjectEnd, vec![]), + ] + ); + assert_stream_equal( + "{\"a\" : 1.0 ,\"b\": [ true ]}", + vec![ + (ObjectStart, vec![]), + (F64Value(1.0), vec![Key("a")]), + (ArrayStart, vec![Key("b")]), + (BooleanValue(true),vec![Key("b"), Index(0)]), + (ArrayEnd, vec![Key("b")]), + (ObjectEnd, vec![]), + ] + ); + assert_stream_equal( + r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#, + vec![ + (ObjectStart, vec![]), + (F64Value(1.0), vec![Key("a")]), + (ArrayStart, vec![Key("b")]), + (BooleanValue(true), vec![Key("b"), Index(0)]), + (StringValue("foo\nbar".to_string()), vec![Key("b"), Index(1)]), + (ObjectStart, vec![Key("b"), Index(2)]), + (ObjectStart, vec![Key("b"), Index(2), Key("c")]), + (NullValue, vec![Key("b"), Index(2), Key("c"), Key("d")]), + (ObjectEnd, vec![Key("b"), Index(2), Key("c")]), + (ObjectEnd, vec![Key("b"), Index(2)]), + (ArrayEnd, vec![Key("b")]), + (ObjectEnd, vec![]), + ] + ); + } + #[test] + #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + fn test_read_array_streaming() { + assert_stream_equal( + "[]", + vec![ + (ArrayStart, vec![]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[ ]", + vec![ + (ArrayStart, vec![]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[true]", + vec![ + (ArrayStart, vec![]), + (BooleanValue(true), vec![Index(0)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[ false ]", + vec![ + (ArrayStart, vec![]), + (BooleanValue(false), vec![Index(0)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[null]", + vec![ + (ArrayStart, vec![]), + (NullValue, vec![Index(0)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[3, 1]", + vec![ + (ArrayStart, vec![]), + (U64Value(3), vec![Index(0)]), + (U64Value(1), vec![Index(1)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "\n[3, 2]\n", + vec![ + (ArrayStart, vec![]), + (U64Value(3), vec![Index(0)]), + (U64Value(2), vec![Index(1)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[2, [4, 1]]", + vec![ + (ArrayStart, vec![]), + (U64Value(2), vec![Index(0)]), + (ArrayStart, vec![Index(1)]), + (U64Value(4), vec![Index(1), Index(0)]), + (U64Value(1), vec![Index(1), Index(1)]), + (ArrayEnd, vec![Index(1)]), + (ArrayEnd, vec![]), + ] + ); + + assert_eq!(last_event("["), Error(SyntaxError(EOFWhileParsingValue, 1, 2))); + + assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2))); + assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3))); + assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4))); + assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + + } + #[test] + fn test_trailing_characters_streaming() { + assert_eq!(last_event("nulla"), Error(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(last_event("truea"), Error(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(last_event("falsea"), Error(SyntaxError(TrailingCharacters, 1, 6))); + assert_eq!(last_event("1a"), Error(SyntaxError(TrailingCharacters, 1, 2))); + assert_eq!(last_event("[]a"), Error(SyntaxError(TrailingCharacters, 1, 3))); + assert_eq!(last_event("{}a"), Error(SyntaxError(TrailingCharacters, 1, 3))); + } + #[test] + fn test_read_identifiers_streaming() { + assert_eq!(Parser::new("null".chars()).next(), Some(NullValue)); + assert_eq!(Parser::new("true".chars()).next(), Some(BooleanValue(true))); + assert_eq!(Parser::new("false".chars()).next(), Some(BooleanValue(false))); + + assert_eq!(last_event("n"), Error(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(last_event("nul"), Error(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(last_event("t"), Error(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(last_event("truz"), Error(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(last_event("f"), Error(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(last_event("faz"), Error(SyntaxError(InvalidSyntax, 1, 3))); + } + + #[test] + fn test_stack() { + let mut stack = Stack::new(); + + assert!(stack.is_empty()); + assert!(stack.len() == 0); + assert!(!stack.last_is_index()); + + stack.push_index(0); + stack.bump_index(); + + assert!(stack.len() == 1); + assert!(stack.is_equal_to(&[Index(1)])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.ends_with(&[Index(1)])); + assert!(stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + + stack.push_key("foo".to_string()); + + assert!(stack.len() == 2); + assert!(stack.is_equal_to(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.ends_with(&[Index(1), Key("foo")])); + assert!(stack.ends_with(&[Key("foo")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + assert!(stack.get(1) == Key("foo")); + + stack.push_key("bar".to_string()); + + assert!(stack.len() == 3); + assert!(stack.is_equal_to(&[Index(1), Key("foo"), Key("bar")])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.starts_with(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1), Key("foo"), Key("bar")])); + assert!(stack.ends_with(&[Key("bar")])); + assert!(stack.ends_with(&[Key("foo"), Key("bar")])); + assert!(stack.ends_with(&[Index(1), Key("foo"), Key("bar")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + assert!(stack.get(1) == Key("foo")); + assert!(stack.get(2) == Key("bar")); + + stack.pop(); + + assert!(stack.len() == 2); + assert!(stack.is_equal_to(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.ends_with(&[Index(1), Key("foo")])); + assert!(stack.ends_with(&[Key("foo")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + assert!(stack.get(1) == Key("foo")); + } + + #[test] + fn test_to_json() { + use std::collections::{HashMap,BTreeMap}; + use super::ToJson; + + let array2 = Array(vec!(U64(1), U64(2))); + let array3 = Array(vec!(U64(1), U64(2), U64(3))); + let object = { + let mut tree_map = BTreeMap::new(); + tree_map.insert("a".to_string(), U64(1)); + tree_map.insert("b".to_string(), U64(2)); + Object(tree_map) + }; + + assert_eq!(array2.to_json(), array2); + assert_eq!(object.to_json(), object); + assert_eq!(3_i.to_json(), I64(3)); + assert_eq!(4_i8.to_json(), I64(4)); + assert_eq!(5_i16.to_json(), I64(5)); + assert_eq!(6_i32.to_json(), I64(6)); + assert_eq!(7_i64.to_json(), I64(7)); + assert_eq!(8_u.to_json(), U64(8)); + assert_eq!(9_u8.to_json(), U64(9)); + assert_eq!(10_u16.to_json(), U64(10)); + assert_eq!(11_u32.to_json(), U64(11)); + assert_eq!(12_u64.to_json(), U64(12)); + assert_eq!(13.0_f32.to_json(), F64(13.0_f64)); + assert_eq!(14.0_f64.to_json(), F64(14.0_f64)); + assert_eq!(().to_json(), Null); + assert_eq!(f32::INFINITY.to_json(), Null); + assert_eq!(f64::NAN.to_json(), Null); + assert_eq!(true.to_json(), Boolean(true)); + assert_eq!(false.to_json(), Boolean(false)); + assert_eq!("abc".to_json(), String("abc".to_string())); + assert_eq!("abc".to_string().to_json(), String("abc".to_string())); + assert_eq!((1u, 2u).to_json(), array2); + assert_eq!((1u, 2u, 3u).to_json(), array3); + assert_eq!([1u, 2].to_json(), array2); + assert_eq!((&[1u, 2, 3]).to_json(), array3); + assert_eq!((vec![1u, 2]).to_json(), array2); + assert_eq!(vec!(1u, 2, 3).to_json(), array3); + let mut tree_map = BTreeMap::new(); + tree_map.insert("a".to_string(), 1u); + tree_map.insert("b".to_string(), 2); + assert_eq!(tree_map.to_json(), object); + let mut hash_map = HashMap::new(); + hash_map.insert("a".to_string(), 1u); + hash_map.insert("b".to_string(), 2); + assert_eq!(hash_map.to_json(), object); + assert_eq!(Some(15i).to_json(), I64(15)); + assert_eq!(Some(15u).to_json(), U64(15)); + assert_eq!(None::.to_json(), Null); + } + + #[bench] + fn bench_streaming_small(b: &mut Bencher) { + b.iter( || { + let mut parser = Parser::new( + r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#.chars() + ); + loop { + match parser.next() { + None => return, + _ => {} + } + } + }); + } + #[bench] + fn bench_small(b: &mut Bencher) { + b.iter( || { + let _ = from_str(r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#); + }); + } + + fn big_json() -> string::String { + let mut src = "[\n".to_string(); + for _ in range(0i, 500) { + src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \ + [1,2,3]},"#); + } + src.push_str("{}]"); + return src; + } + + #[bench] + fn bench_streaming_large(b: &mut Bencher) { + let src = big_json(); + b.iter( || { + let mut parser = Parser::new(src.chars()); + loop { + match parser.next() { + None => return, + _ => {} + } + } + }); + } + #[bench] + fn bench_large(b: &mut Bencher) { + let src = big_json(); + b.iter( || { let _ = from_str(src.as_slice()); }); + } +} diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 1ec6a2af309a7..8ad2013f9368f 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -40,11 +40,25 @@ extern crate collections; pub use self::serialize::{Decoder, Encoder, Decodable, Encodable, DecoderHelpers, EncoderHelpers}; +#[cfg(stage0)] +#[path = "serialize_stage0.rs"] mod serialize; +#[cfg(not(stage0))] +mod serialize; + +#[cfg(stage0)] +#[path = "collection_impls_stage0.rs"] +mod collection_impls; +#[cfg(not(stage0))] mod collection_impls; pub mod base64; pub mod hex; + +#[cfg(stage0)] +#[path = "json_stage0.rs"] +pub mod json; +#[cfg(not(stage0))] pub mod json; mod rustc_serialize { diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 558f9e603e159..0646ee1758fc0 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -19,406 +19,424 @@ use std::rc::Rc; use std::cell::{Cell, RefCell}; use std::sync::Arc; -pub trait Encoder { +pub trait Encoder { + type Error; + // Primitive types: - fn emit_nil(&mut self) -> Result<(), E>; - fn emit_uint(&mut self, v: uint) -> Result<(), E>; - fn emit_u64(&mut self, v: u64) -> Result<(), E>; - fn emit_u32(&mut self, v: u32) -> Result<(), E>; - fn emit_u16(&mut self, v: u16) -> Result<(), E>; - fn emit_u8(&mut self, v: u8) -> Result<(), E>; - fn emit_int(&mut self, v: int) -> Result<(), E>; - fn emit_i64(&mut self, v: i64) -> Result<(), E>; - fn emit_i32(&mut self, v: i32) -> Result<(), E>; - fn emit_i16(&mut self, v: i16) -> Result<(), E>; - fn emit_i8(&mut self, v: i8) -> Result<(), E>; - fn emit_bool(&mut self, v: bool) -> Result<(), E>; - fn emit_f64(&mut self, v: f64) -> Result<(), E>; - fn emit_f32(&mut self, v: f32) -> Result<(), E>; - fn emit_char(&mut self, v: char) -> Result<(), E>; - fn emit_str(&mut self, v: &str) -> Result<(), E>; + fn emit_nil(&mut self) -> Result<(), Self::Error>; + fn emit_uint(&mut self, v: uint) -> Result<(), Self::Error>; + fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>; + fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error>; + fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error>; + fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error>; + fn emit_int(&mut self, v: int) -> Result<(), Self::Error>; + fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error>; + fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error>; + fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error>; + fn emit_i8(&mut self, v: i8) -> Result<(), Self::Error>; + fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error>; + fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error>; + fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error>; + fn emit_char(&mut self, v: char) -> Result<(), Self::Error>; + fn emit_str(&mut self, v: &str) -> Result<(), Self::Error>; // Compound types: - fn emit_enum(&mut self, name: &str, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_enum(&mut self, name: &str, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; fn emit_enum_variant(&mut self, v_name: &str, v_id: uint, len: uint, - f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_enum_variant_arg(&mut self, a_idx: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; fn emit_enum_struct_variant(&mut self, v_name: &str, v_id: uint, len: uint, - f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; fn emit_enum_struct_variant_field(&mut self, f_name: &str, f_idx: uint, - f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + fn emit_struct(&mut self, name: &str, len: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + fn emit_tuple(&mut self, len: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + fn emit_tuple_struct(&mut self, name: &str, len: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + // Specialized types: + fn emit_option(&mut self, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_option_none(&mut self) -> Result<(), Self::Error>; + fn emit_option_some(&mut self, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_seq(&mut self, len: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_seq_elt(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_tuple(&mut self, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_tuple_arg(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_map(&mut self, len: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_map_elt_key(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnMut(&mut Self) -> Result<(), Self::Error>; + fn emit_map_elt_val(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; +} - fn emit_tuple_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; +pub trait Decoder { + type Error; - // Specialized types: - fn emit_option(&mut self, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_option_none(&mut self) -> Result<(), E>; - fn emit_option_some(&mut self, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - - fn emit_seq(&mut self, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_seq_elt(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - - fn emit_map(&mut self, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_map_elt_key(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnMut(&mut Self) -> Result<(), E>; - fn emit_map_elt_val(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; -} - -pub trait Decoder { // Primitive types: - fn read_nil(&mut self) -> Result<(), E>; - fn read_uint(&mut self) -> Result; - fn read_u64(&mut self) -> Result; - fn read_u32(&mut self) -> Result; - fn read_u16(&mut self) -> Result; - fn read_u8(&mut self) -> Result; - fn read_int(&mut self) -> Result; - fn read_i64(&mut self) -> Result; - fn read_i32(&mut self) -> Result; - fn read_i16(&mut self) -> Result; - fn read_i8(&mut self) -> Result; - fn read_bool(&mut self) -> Result; - fn read_f64(&mut self) -> Result; - fn read_f32(&mut self) -> Result; - fn read_char(&mut self) -> Result; - fn read_str(&mut self) -> Result; + fn read_nil(&mut self) -> Result<(), Self::Error>; + fn read_uint(&mut self) -> Result; + fn read_u64(&mut self) -> Result; + fn read_u32(&mut self) -> Result; + fn read_u16(&mut self) -> Result; + fn read_u8(&mut self) -> Result; + fn read_int(&mut self) -> Result; + fn read_i64(&mut self) -> Result; + fn read_i32(&mut self) -> Result; + fn read_i16(&mut self) -> Result; + fn read_i8(&mut self) -> Result; + fn read_bool(&mut self) -> Result; + fn read_f64(&mut self) -> Result; + fn read_f32(&mut self) -> Result; + fn read_char(&mut self) -> Result; + fn read_str(&mut self) -> Result; // Compound types: - fn read_enum(&mut self, name: &str, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_enum_variant(&mut self, names: &[&str], f: F) -> Result where - F: FnMut(&mut Self, uint) -> Result; - fn read_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> Result where - F: FnMut(&mut Self, uint) -> Result; + fn read_enum(&mut self, name: &str, f: F) -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_enum_variant(&mut self, names: &[&str], f: F) + -> Result + where F: FnMut(&mut Self, uint) -> Result; + fn read_enum_variant_arg(&mut self, a_idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_enum_struct_variant(&mut self, names: &[&str], f: F) + -> Result + where F: FnMut(&mut Self, uint) -> Result; fn read_enum_struct_variant_field(&mut self, &f_name: &str, f_idx: uint, f: F) - -> Result where - F: FnOnce(&mut Self) -> Result; + -> Result + where F: FnOnce(&mut Self) -> Result; - fn read_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; + fn read_struct(&mut self, s_name: &str, len: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; fn read_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) - -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_tuple(&mut self, len: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - fn read_tuple_arg(&mut self, a_idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_tuple_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - fn read_tuple_struct_arg(&mut self, a_idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; + -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_tuple(&mut self, len: uint, f: F) -> Result + where F: FnOnce(&mut Self) -> Result; + fn read_tuple_arg(&mut self, a_idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_tuple_struct(&mut self, s_name: &str, len: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + fn read_tuple_struct_arg(&mut self, a_idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; // Specialized types: - fn read_option(&mut self, f: F) -> Result where - F: FnMut(&mut Self, bool) -> Result; - - fn read_seq(&mut self, f: F) -> Result where - F: FnOnce(&mut Self, uint) -> Result; - fn read_seq_elt(&mut self, idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_map(&mut self, f: F) -> Result where - F: FnOnce(&mut Self, uint) -> Result; - fn read_map_elt_key(&mut self, idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - fn read_map_elt_val(&mut self, idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; + fn read_option(&mut self, f: F) -> Result + where F: FnMut(&mut Self, bool) -> Result; + + fn read_seq(&mut self, f: F) -> Result + where F: FnOnce(&mut Self, uint) -> Result; + fn read_seq_elt(&mut self, idx: uint, f: F) -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_map(&mut self, f: F) -> Result + where F: FnOnce(&mut Self, uint) -> Result; + fn read_map_elt_key(&mut self, idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + fn read_map_elt_val(&mut self, idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; // Failure - fn error(&mut self, err: &str) -> E; + fn error(&mut self, err: &str) -> Self::Error; } -pub trait Encodable, E> for Sized? { - fn encode(&self, s: &mut S) -> Result<(), E>; +pub trait Encodable for Sized? { + fn encode(&self, s: &mut S) -> Result<(), S::Error>; } -pub trait Decodable, E> { - fn decode(d: &mut D) -> Result; +pub trait Decodable { + fn decode(d: &mut D) -> Result; } -impl> Encodable for uint { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for uint { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_uint(*self) } } -impl> Decodable for uint { - fn decode(d: &mut D) -> Result { +impl Decodable for uint { + fn decode(d: &mut D) -> Result { d.read_uint() } } -impl> Encodable for u8 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u8 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u8(*self) } } -impl> Decodable for u8 { - fn decode(d: &mut D) -> Result { +impl Decodable for u8 { + fn decode(d: &mut D) -> Result { d.read_u8() } } -impl> Encodable for u16 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u16 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u16(*self) } } -impl> Decodable for u16 { - fn decode(d: &mut D) -> Result { +impl Decodable for u16 { + fn decode(d: &mut D) -> Result { d.read_u16() } } -impl> Encodable for u32 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u32 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u32(*self) } } -impl> Decodable for u32 { - fn decode(d: &mut D) -> Result { +impl Decodable for u32 { + fn decode(d: &mut D) -> Result { d.read_u32() } } -impl> Encodable for u64 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u64 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u64(*self) } } -impl> Decodable for u64 { - fn decode(d: &mut D) -> Result { +impl Decodable for u64 { + fn decode(d: &mut D) -> Result { d.read_u64() } } -impl> Encodable for int { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for int { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_int(*self) } } -impl> Decodable for int { - fn decode(d: &mut D) -> Result { +impl Decodable for int { + fn decode(d: &mut D) -> Result { d.read_int() } } -impl> Encodable for i8 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i8 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i8(*self) } } -impl> Decodable for i8 { - fn decode(d: &mut D) -> Result { +impl Decodable for i8 { + fn decode(d: &mut D) -> Result { d.read_i8() } } -impl> Encodable for i16 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i16 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i16(*self) } } -impl> Decodable for i16 { - fn decode(d: &mut D) -> Result { +impl Decodable for i16 { + fn decode(d: &mut D) -> Result { d.read_i16() } } -impl> Encodable for i32 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i32 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i32(*self) } } -impl> Decodable for i32 { - fn decode(d: &mut D) -> Result { +impl Decodable for i32 { + fn decode(d: &mut D) -> Result { d.read_i32() } } -impl> Encodable for i64 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i64 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i64(*self) } } -impl> Decodable for i64 { - fn decode(d: &mut D) -> Result { +impl Decodable for i64 { + fn decode(d: &mut D) -> Result { d.read_i64() } } -impl> Encodable for str { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for str { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_str(self) } } -impl> Encodable for String { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for String { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_str(self[]) } } -impl> Decodable for String { - fn decode(d: &mut D) -> Result { +impl Decodable for String { + fn decode(d: &mut D) -> Result { d.read_str() } } -impl> Encodable for f32 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for f32 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_f32(*self) } } -impl> Decodable for f32 { - fn decode(d: &mut D) -> Result { +impl Decodable for f32 { + fn decode(d: &mut D) -> Result { d.read_f32() } } -impl> Encodable for f64 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for f64 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_f64(*self) } } -impl> Decodable for f64 { - fn decode(d: &mut D) -> Result { +impl Decodable for f64 { + fn decode(d: &mut D) -> Result { d.read_f64() } } -impl> Encodable for bool { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for bool { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_bool(*self) } } -impl> Decodable for bool { - fn decode(d: &mut D) -> Result { +impl Decodable for bool { + fn decode(d: &mut D) -> Result { d.read_bool() } } -impl> Encodable for char { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for char { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_char(*self) } } -impl> Decodable for char { - fn decode(d: &mut D) -> Result { +impl Decodable for char { + fn decode(d: &mut D) -> Result { d.read_char() } } -impl> Encodable for () { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for () { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_nil() } } -impl> Decodable for () { - fn decode(d: &mut D) -> Result<(), E> { +impl Decodable for () { + fn decode(d: &mut D) -> Result<(), D::Error> { d.read_nil() } } -impl<'a, E, S: Encoder, Sized? T: Encodable> Encodable for &'a T { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl<'a, Sized? T: Encodable> Encodable for &'a T { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl, Sized? T: Encodable> Encodable for Box { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Box { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl, T: Decodable> Decodable for Box { - fn decode(d: &mut D) -> Result, E> { +impl< T: Decodable> Decodable for Box { + fn decode(d: &mut D) -> Result, D::Error> { Ok(box try!(Decodable::decode(d))) } } -impl, T: Decodable> Decodable for Box<[T]> { - fn decode(d: &mut D) -> Result, E> { +impl< T: Decodable> Decodable for Box<[T]> { + fn decode(d: &mut D) -> Result, D::Error> { let v: Vec = try!(Decodable::decode(d)); Ok(v.into_boxed_slice()) } } -impl,T:Encodable> Encodable for Rc { +impl Encodable for Rc { #[inline] - fn encode(&self, s: &mut S) -> Result<(), E> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl,T:Decodable> Decodable for Rc { +impl Decodable for Rc { #[inline] - fn decode(d: &mut D) -> Result, E> { + fn decode(d: &mut D) -> Result, D::Error> { Ok(Rc::new(try!(Decodable::decode(d)))) } } -impl,T:Encodable> Encodable for [T] { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for [T] { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))) @@ -428,8 +446,8 @@ impl,T:Encodable> Encodable for [T] { } } -impl,T:Encodable> Encodable for Vec { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Vec { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))) @@ -439,8 +457,8 @@ impl,T:Encodable> Encodable for Vec { } } -impl,T:Decodable> Decodable for Vec { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Vec { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut v = Vec::with_capacity(len); for i in range(0, len) { @@ -451,8 +469,8 @@ impl,T:Decodable> Decodable for Vec { } } -impl,T:Encodable> Encodable for Option { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Option { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_option(|s| { match *self { None => s.emit_option_none(), @@ -462,8 +480,8 @@ impl,T:Encodable> Encodable for Option { } } -impl,T:Decodable> Decodable for Option { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Option { + fn decode(d: &mut D) -> Result, D::Error> { d.read_option(|d, b| { if b { Ok(Some(try!(Decodable::decode(d)))) @@ -487,22 +505,23 @@ macro_rules! count_idents { macro_rules! tuple { () => (); ( $($name:ident,)+ ) => ( - impl,$($name:Decodable),*> Decodable for ($($name,)*) { + impl<$($name:Decodable),*> Decodable for ($($name,)*) { #[allow(non_snake_case)] - fn decode(d: &mut D) -> Result<($($name,)*), E> { + fn decode(d: &mut D) -> Result<($($name,)*), D::Error> { let len: uint = count_idents!($($name),*); d.read_tuple(len, |d| { let mut i = 0; - let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name,E> { + let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, + |d| -> Result<$name,D::Error> { Decodable::decode(d) })),)*); return Ok(ret); }) } } - impl,$($name:Encodable),*> Encodable for ($($name,)*) { + impl<$($name:Encodable),*> Encodable for ($($name,)*) { #[allow(non_snake_case)] - fn encode(&self, s: &mut S) -> Result<(), E> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { let ($(ref $name,)*) = *self; let mut n = 0; $(let $name = $name; n += 1;)* @@ -519,40 +538,40 @@ macro_rules! tuple { tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } -impl> Encodable for path::posix::Path { - fn encode(&self, e: &mut S) -> Result<(), E> { +impl Encodable for path::posix::Path { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { self.as_vec().encode(e) } } -impl> Decodable for path::posix::Path { - fn decode(d: &mut D) -> Result { +impl Decodable for path::posix::Path { + fn decode(d: &mut D) -> Result { let bytes: Vec = try!(Decodable::decode(d)); Ok(path::posix::Path::new(bytes)) } } -impl> Encodable for path::windows::Path { - fn encode(&self, e: &mut S) -> Result<(), E> { +impl Encodable for path::windows::Path { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { self.as_vec().encode(e) } } -impl> Decodable for path::windows::Path { - fn decode(d: &mut D) -> Result { +impl Decodable for path::windows::Path { + fn decode(d: &mut D) -> Result { let bytes: Vec = try!(Decodable::decode(d)); Ok(path::windows::Path::new(bytes)) } } -impl, T: Encodable + Copy> Encodable for Cell { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Cell { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { self.get().encode(s) } } -impl, T: Decodable + Copy> Decodable for Cell { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Cell { + fn decode(d: &mut D) -> Result, D::Error> { Ok(Cell::new(try!(Decodable::decode(d)))) } } @@ -562,26 +581,26 @@ impl, T: Decodable + Copy> Decodable for Cell { // `encoder.error("attempting to Encode borrowed RefCell")` // from `encode` when `try_borrow` returns `None`. -impl, T: Encodable> Encodable for RefCell { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for RefCell { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { self.borrow().encode(s) } } -impl, T: Decodable> Decodable for RefCell { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for RefCell { + fn decode(d: &mut D) -> Result, D::Error> { Ok(RefCell::new(try!(Decodable::decode(d)))) } } -impl, T:Encodable> Encodable for Arc { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Arc { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl,T:Decodable+Send+Sync> Decodable for Arc { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Arc { + fn decode(d: &mut D) -> Result, D::Error> { Ok(Arc::new(try!(Decodable::decode(d)))) } } @@ -589,14 +608,15 @@ impl,T:Decodable+Send+Sync> Decodable for Arc { // ___________________________________________________________________________ // Helper routines -pub trait EncoderHelpers { - fn emit_from_vec(&mut self, v: &[T], f: F) -> Result<(), E> where - F: FnMut(&mut Self, &T) -> Result<(), E>; +pub trait EncoderHelpers: Encoder { + fn emit_from_vec(&mut self, v: &[T], f: F) + -> Result<(), ::Error> + where F: FnMut(&mut Self, &T) -> Result<(), ::Error>; } -impl> EncoderHelpers for S { - fn emit_from_vec(&mut self, v: &[T], mut f: F) -> Result<(), E> where - F: FnMut(&mut S, &T) -> Result<(), E>, +impl EncoderHelpers for S { + fn emit_from_vec(&mut self, v: &[T], mut f: F) -> Result<(), S::Error> where + F: FnMut(&mut S, &T) -> Result<(), S::Error>, { self.emit_seq(v.len(), |this| { for (i, e) in v.iter().enumerate() { @@ -609,14 +629,15 @@ impl> EncoderHelpers for S { } } -pub trait DecoderHelpers { - fn read_to_vec(&mut self, f: F) -> Result, E> where - F: FnMut(&mut Self) -> Result; +pub trait DecoderHelpers: Decoder { + fn read_to_vec(&mut self, f: F) + -> Result, ::Error> where + F: FnMut(&mut Self) -> Result::Error>; } -impl> DecoderHelpers for D { - fn read_to_vec(&mut self, mut f: F) -> Result, E> where F: - FnMut(&mut D) -> Result, +impl DecoderHelpers for D { + fn read_to_vec(&mut self, mut f: F) -> Result, D::Error> where F: + FnMut(&mut D) -> Result, { self.read_seq(|this, len| { let mut v = Vec::with_capacity(len); diff --git a/src/libserialize/serialize_stage0.rs b/src/libserialize/serialize_stage0.rs new file mode 100644 index 0000000000000..558f9e603e159 --- /dev/null +++ b/src/libserialize/serialize_stage0.rs @@ -0,0 +1,629 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support code for encoding and decoding types. + +/* +Core encoding and decoding interfaces. +*/ + +use std::path; +use std::rc::Rc; +use std::cell::{Cell, RefCell}; +use std::sync::Arc; + +pub trait Encoder { + // Primitive types: + fn emit_nil(&mut self) -> Result<(), E>; + fn emit_uint(&mut self, v: uint) -> Result<(), E>; + fn emit_u64(&mut self, v: u64) -> Result<(), E>; + fn emit_u32(&mut self, v: u32) -> Result<(), E>; + fn emit_u16(&mut self, v: u16) -> Result<(), E>; + fn emit_u8(&mut self, v: u8) -> Result<(), E>; + fn emit_int(&mut self, v: int) -> Result<(), E>; + fn emit_i64(&mut self, v: i64) -> Result<(), E>; + fn emit_i32(&mut self, v: i32) -> Result<(), E>; + fn emit_i16(&mut self, v: i16) -> Result<(), E>; + fn emit_i8(&mut self, v: i8) -> Result<(), E>; + fn emit_bool(&mut self, v: bool) -> Result<(), E>; + fn emit_f64(&mut self, v: f64) -> Result<(), E>; + fn emit_f32(&mut self, v: f32) -> Result<(), E>; + fn emit_char(&mut self, v: char) -> Result<(), E>; + fn emit_str(&mut self, v: &str) -> Result<(), E>; + + // Compound types: + fn emit_enum(&mut self, name: &str, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_enum_variant(&mut self, v_name: &str, + v_id: uint, + len: uint, + f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_enum_struct_variant(&mut self, v_name: &str, + v_id: uint, + len: uint, + f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_enum_struct_variant_field(&mut self, + f_name: &str, + f_idx: uint, + f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_tuple(&mut self, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_tuple_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + // Specialized types: + fn emit_option(&mut self, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_option_none(&mut self) -> Result<(), E>; + fn emit_option_some(&mut self, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_seq(&mut self, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_seq_elt(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_map(&mut self, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_map_elt_key(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnMut(&mut Self) -> Result<(), E>; + fn emit_map_elt_val(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; +} + +pub trait Decoder { + // Primitive types: + fn read_nil(&mut self) -> Result<(), E>; + fn read_uint(&mut self) -> Result; + fn read_u64(&mut self) -> Result; + fn read_u32(&mut self) -> Result; + fn read_u16(&mut self) -> Result; + fn read_u8(&mut self) -> Result; + fn read_int(&mut self) -> Result; + fn read_i64(&mut self) -> Result; + fn read_i32(&mut self) -> Result; + fn read_i16(&mut self) -> Result; + fn read_i8(&mut self) -> Result; + fn read_bool(&mut self) -> Result; + fn read_f64(&mut self) -> Result; + fn read_f32(&mut self) -> Result; + fn read_char(&mut self) -> Result; + fn read_str(&mut self) -> Result; + + // Compound types: + fn read_enum(&mut self, name: &str, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_enum_variant(&mut self, names: &[&str], f: F) -> Result where + F: FnMut(&mut Self, uint) -> Result; + fn read_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> Result where + F: FnMut(&mut Self, uint) -> Result; + fn read_enum_struct_variant_field(&mut self, + &f_name: &str, + f_idx: uint, + f: F) + -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_struct_field(&mut self, + f_name: &str, + f_idx: uint, + f: F) + -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_tuple(&mut self, len: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_tuple_arg(&mut self, a_idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_tuple_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_tuple_struct_arg(&mut self, a_idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + // Specialized types: + fn read_option(&mut self, f: F) -> Result where + F: FnMut(&mut Self, bool) -> Result; + + fn read_seq(&mut self, f: F) -> Result where + F: FnOnce(&mut Self, uint) -> Result; + fn read_seq_elt(&mut self, idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_map(&mut self, f: F) -> Result where + F: FnOnce(&mut Self, uint) -> Result; + fn read_map_elt_key(&mut self, idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_map_elt_val(&mut self, idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + // Failure + fn error(&mut self, err: &str) -> E; +} + +pub trait Encodable, E> for Sized? { + fn encode(&self, s: &mut S) -> Result<(), E>; +} + +pub trait Decodable, E> { + fn decode(d: &mut D) -> Result; +} + +impl> Encodable for uint { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_uint(*self) + } +} + +impl> Decodable for uint { + fn decode(d: &mut D) -> Result { + d.read_uint() + } +} + +impl> Encodable for u8 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u8(*self) + } +} + +impl> Decodable for u8 { + fn decode(d: &mut D) -> Result { + d.read_u8() + } +} + +impl> Encodable for u16 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u16(*self) + } +} + +impl> Decodable for u16 { + fn decode(d: &mut D) -> Result { + d.read_u16() + } +} + +impl> Encodable for u32 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u32(*self) + } +} + +impl> Decodable for u32 { + fn decode(d: &mut D) -> Result { + d.read_u32() + } +} + +impl> Encodable for u64 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u64(*self) + } +} + +impl> Decodable for u64 { + fn decode(d: &mut D) -> Result { + d.read_u64() + } +} + +impl> Encodable for int { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_int(*self) + } +} + +impl> Decodable for int { + fn decode(d: &mut D) -> Result { + d.read_int() + } +} + +impl> Encodable for i8 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i8(*self) + } +} + +impl> Decodable for i8 { + fn decode(d: &mut D) -> Result { + d.read_i8() + } +} + +impl> Encodable for i16 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i16(*self) + } +} + +impl> Decodable for i16 { + fn decode(d: &mut D) -> Result { + d.read_i16() + } +} + +impl> Encodable for i32 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i32(*self) + } +} + +impl> Decodable for i32 { + fn decode(d: &mut D) -> Result { + d.read_i32() + } +} + +impl> Encodable for i64 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i64(*self) + } +} + +impl> Decodable for i64 { + fn decode(d: &mut D) -> Result { + d.read_i64() + } +} + +impl> Encodable for str { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_str(self) + } +} + +impl> Encodable for String { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_str(self[]) + } +} + +impl> Decodable for String { + fn decode(d: &mut D) -> Result { + d.read_str() + } +} + +impl> Encodable for f32 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_f32(*self) + } +} + +impl> Decodable for f32 { + fn decode(d: &mut D) -> Result { + d.read_f32() + } +} + +impl> Encodable for f64 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_f64(*self) + } +} + +impl> Decodable for f64 { + fn decode(d: &mut D) -> Result { + d.read_f64() + } +} + +impl> Encodable for bool { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_bool(*self) + } +} + +impl> Decodable for bool { + fn decode(d: &mut D) -> Result { + d.read_bool() + } +} + +impl> Encodable for char { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_char(*self) + } +} + +impl> Decodable for char { + fn decode(d: &mut D) -> Result { + d.read_char() + } +} + +impl> Encodable for () { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_nil() + } +} + +impl> Decodable for () { + fn decode(d: &mut D) -> Result<(), E> { + d.read_nil() + } +} + +impl<'a, E, S: Encoder, Sized? T: Encodable> Encodable for &'a T { + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl, Sized? T: Encodable> Encodable for Box { + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl, T: Decodable> Decodable for Box { + fn decode(d: &mut D) -> Result, E> { + Ok(box try!(Decodable::decode(d))) + } +} + +impl, T: Decodable> Decodable for Box<[T]> { + fn decode(d: &mut D) -> Result, E> { + let v: Vec = try!(Decodable::decode(d)); + Ok(v.into_boxed_slice()) + } +} + +impl,T:Encodable> Encodable for Rc { + #[inline] + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl,T:Decodable> Decodable for Rc { + #[inline] + fn decode(d: &mut D) -> Result, E> { + Ok(Rc::new(try!(Decodable::decode(d)))) + } +} + +impl,T:Encodable> Encodable for [T] { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))) + } + Ok(()) + }) + } +} + +impl,T:Encodable> Encodable for Vec { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))) + } + Ok(()) + }) + } +} + +impl,T:Decodable> Decodable for Vec { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut v = Vec::with_capacity(len); + for i in range(0, len) { + v.push(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(v) + }) + } +} + +impl,T:Encodable> Encodable for Option { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_option(|s| { + match *self { + None => s.emit_option_none(), + Some(ref v) => s.emit_option_some(|s| v.encode(s)), + } + }) + } +} + +impl,T:Decodable> Decodable for Option { + fn decode(d: &mut D) -> Result, E> { + d.read_option(|d, b| { + if b { + Ok(Some(try!(Decodable::decode(d)))) + } else { + Ok(None) + } + }) + } +} + +macro_rules! peel { + ($name:ident, $($other:ident,)*) => (tuple! { $($other,)* }) +} + +/// Evaluates to the number of identifiers passed to it, for example: `count_idents!(a, b, c) == 3 +macro_rules! count_idents { + () => { 0u }; + ($_i:ident $(, $rest:ident)*) => { 1 + count_idents!($($rest),*) } +} + +macro_rules! tuple { + () => (); + ( $($name:ident,)+ ) => ( + impl,$($name:Decodable),*> Decodable for ($($name,)*) { + #[allow(non_snake_case)] + fn decode(d: &mut D) -> Result<($($name,)*), E> { + let len: uint = count_idents!($($name),*); + d.read_tuple(len, |d| { + let mut i = 0; + let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name,E> { + Decodable::decode(d) + })),)*); + return Ok(ret); + }) + } + } + impl,$($name:Encodable),*> Encodable for ($($name,)*) { + #[allow(non_snake_case)] + fn encode(&self, s: &mut S) -> Result<(), E> { + let ($(ref $name,)*) = *self; + let mut n = 0; + $(let $name = $name; n += 1;)* + s.emit_tuple(n, |s| { + let mut i = 0; + $(try!(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s)));)* + Ok(()) + }) + } + } + peel! { $($name,)* } + ) +} + +tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } + +impl> Encodable for path::posix::Path { + fn encode(&self, e: &mut S) -> Result<(), E> { + self.as_vec().encode(e) + } +} + +impl> Decodable for path::posix::Path { + fn decode(d: &mut D) -> Result { + let bytes: Vec = try!(Decodable::decode(d)); + Ok(path::posix::Path::new(bytes)) + } +} + +impl> Encodable for path::windows::Path { + fn encode(&self, e: &mut S) -> Result<(), E> { + self.as_vec().encode(e) + } +} + +impl> Decodable for path::windows::Path { + fn decode(d: &mut D) -> Result { + let bytes: Vec = try!(Decodable::decode(d)); + Ok(path::windows::Path::new(bytes)) + } +} + +impl, T: Encodable + Copy> Encodable for Cell { + fn encode(&self, s: &mut S) -> Result<(), E> { + self.get().encode(s) + } +} + +impl, T: Decodable + Copy> Decodable for Cell { + fn decode(d: &mut D) -> Result, E> { + Ok(Cell::new(try!(Decodable::decode(d)))) + } +} + +// FIXME: #15036 +// Should use `try_borrow`, returning a +// `encoder.error("attempting to Encode borrowed RefCell")` +// from `encode` when `try_borrow` returns `None`. + +impl, T: Encodable> Encodable for RefCell { + fn encode(&self, s: &mut S) -> Result<(), E> { + self.borrow().encode(s) + } +} + +impl, T: Decodable> Decodable for RefCell { + fn decode(d: &mut D) -> Result, E> { + Ok(RefCell::new(try!(Decodable::decode(d)))) + } +} + +impl, T:Encodable> Encodable for Arc { + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl,T:Decodable+Send+Sync> Decodable for Arc { + fn decode(d: &mut D) -> Result, E> { + Ok(Arc::new(try!(Decodable::decode(d)))) + } +} + +// ___________________________________________________________________________ +// Helper routines + +pub trait EncoderHelpers { + fn emit_from_vec(&mut self, v: &[T], f: F) -> Result<(), E> where + F: FnMut(&mut Self, &T) -> Result<(), E>; +} + +impl> EncoderHelpers for S { + fn emit_from_vec(&mut self, v: &[T], mut f: F) -> Result<(), E> where + F: FnMut(&mut S, &T) -> Result<(), E>, + { + self.emit_seq(v.len(), |this| { + for (i, e) in v.iter().enumerate() { + try!(this.emit_seq_elt(i, |this| { + f(this, e) + })); + } + Ok(()) + }) + } +} + +pub trait DecoderHelpers { + fn read_to_vec(&mut self, f: F) -> Result, E> where + F: FnMut(&mut Self) -> Result; +} + +impl> DecoderHelpers for D { + fn read_to_vec(&mut self, mut f: F) -> Result, E> where F: + FnMut(&mut D) -> Result, + { + self.read_seq(|this, len| { + let mut v = Vec::with_capacity(len); + for i in range(0, len) { + v.push(try!(this.read_seq_elt(i, |this| f(this)))); + } + Ok(v) + }) + } +} diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 03b9eaf76b94f..c9d27e304ff15 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -182,18 +182,34 @@ impl Name { /// A mark represents a unique id associated with a macro expansion pub type Mrk = u32; +#[cfg(stage0)] impl, E> Encodable for Ident { fn encode(&self, s: &mut S) -> Result<(), E> { s.emit_str(token::get_ident(*self).get()) } } +#[cfg(not(stage0))] +impl Encodable for Ident { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(token::get_ident(*self).get()) + } +} + +#[cfg(stage0)] impl, E> Decodable for Ident { fn decode(d: &mut D) -> Result { Ok(str_to_ident(try!(d.read_str())[])) } } +#[cfg(not(stage0))] +impl Decodable for Ident { + fn decode(d: &mut D) -> Result { + Ok(str_to_ident(try!(d.read_str())[])) + } +} + /// Function name (not all functions have names) pub type FnIdent = Option; @@ -1686,27 +1702,7 @@ mod test { // are ASTs encodable? #[test] fn check_asts_encodable() { - use std::io; - let e = Crate { - module: Mod { - inner: Span { - lo: BytePos(11), - hi: BytePos(19), - expn_id: NO_EXPANSION, - }, - view_items: Vec::new(), - items: Vec::new(), - }, - attrs: Vec::new(), - config: Vec::new(), - span: Span { - lo: BytePos(10), - hi: BytePos(20), - expn_id: NO_EXPANSION, - }, - exported_macros: Vec::new(), - }; - // doesn't matter which encoder we use.... - let _f = &e as &serialize::Encodable; + fn assert_encodable() {} + assert_encodable::(); } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 2c7bbcb6faf72..a49f2614cd787 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -120,6 +120,7 @@ impl PartialEq for Span { impl Eq for Span {} +#[cfg(stage0)] impl, E> Encodable for Span { /* Note #1972 -- spans are encoded but not decoded */ fn encode(&self, s: &mut S) -> Result<(), E> { @@ -127,12 +128,28 @@ impl, E> Encodable for Span { } } +#[cfg(not(stage0))] +impl Encodable for Span { + /* Note #1972 -- spans are encoded but not decoded */ + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_nil() + } +} + +#[cfg(stage0)] impl, E> Decodable for Span { fn decode(_d: &mut D) -> Result { Ok(DUMMY_SP) } } +#[cfg(not(stage0))] +impl Decodable for Span { + fn decode(_d: &mut D) -> Result { + Ok(DUMMY_SP) + } +} + pub fn spanned(lo: BytePos, hi: BytePos, t: T) -> Spanned { respan(mk_sp(lo, hi), t) } diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 882136cb86259..c0631b8350b8c 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -52,27 +52,29 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: Path::new_(vec!(krate, "Decodable"), None, - vec!(box Literal(Path::new_local("__D")), - box Literal(Path::new_local("__E"))), true), + path: Path::new_(vec!(krate, "Decodable"), None, vec!(), true), additional_bounds: Vec::new(), - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("__D", vec!(Path::new_( - vec!(krate, "Decoder"), None, - vec!(box Literal(Path::new_local("__E"))), true))), - ("__E", vec!())) - }, + generics: LifetimeBounds::empty(), methods: vec!( MethodDef { name: "decode", - generics: LifetimeBounds::empty(), + generics: LifetimeBounds { + lifetimes: Vec::new(), + bounds: vec!(("__D", vec!(Path::new_( + vec!(krate, "Decoder"), None, + vec!(), true)))) + }, explicit_self: None, args: vec!(Ptr(box Literal(Path::new_local("__D")), Borrowed(None, MutMutable))), - ret_ty: Literal(Path::new_(vec!("std", "result", "Result"), None, - vec!(box Self, - box Literal(Path::new_local("__E"))), true)), + ret_ty: Literal(Path::new_( + vec!("std", "result", "Result"), + None, + vec!(box Self, box Literal(Path::new_( + vec!["__D", "Error"], None, vec![], false + ))), + true + )), attributes: Vec::new(), combine_substructure: combine_substructure(|a, b, c| { decodable_substructure(a, b, c, krate) diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index b2c929123d586..4323d2979cc06 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -128,29 +128,29 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: Path::new_(vec!(krate, "Encodable"), None, - vec!(box Literal(Path::new_local("__S")), - box Literal(Path::new_local("__E"))), true), + path: Path::new_(vec!(krate, "Encodable"), None, vec!(), true), additional_bounds: Vec::new(), - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("__S", vec!(Path::new_( - vec!(krate, "Encoder"), None, - vec!(box Literal(Path::new_local("__E"))), true))), - ("__E", vec!())) - }, + generics: LifetimeBounds::empty(), methods: vec!( MethodDef { name: "encode", - generics: LifetimeBounds::empty(), + generics: LifetimeBounds { + lifetimes: Vec::new(), + bounds: vec!(("__S", vec!(Path::new_( + vec!(krate, "Encoder"), None, + vec!(), true)))) + }, explicit_self: borrowed_explicit_self(), args: vec!(Ptr(box Literal(Path::new_local("__S")), Borrowed(None, MutMutable))), - ret_ty: Literal(Path::new_(vec!("std", "result", "Result"), - None, - vec!(box Tuple(Vec::new()), - box Literal(Path::new_local("__E"))), - true)), + ret_ty: Literal(Path::new_( + vec!("std", "result", "Result"), + None, + vec!(box Tuple(Vec::new()), box Literal(Path::new_( + vec!["__S", "Error"], None, vec![], false + ))), + true + )), attributes: Vec::new(), combine_substructure: combine_substructure(|a, b, c| { encodable_substructure(a, b, c) diff --git a/src/libsyntax/owned_slice.rs b/src/libsyntax/owned_slice.rs index b87e2c6abbc0c..2a27431a0868c 100644 --- a/src/libsyntax/owned_slice.rs +++ b/src/libsyntax/owned_slice.rs @@ -82,12 +82,21 @@ impl FromIterator for OwnedSlice { } } +#[cfg(stage0)] impl, T: Encodable, E> Encodable for OwnedSlice { fn encode(&self, s: &mut S) -> Result<(), E> { self.as_slice().encode(s) } } +#[cfg(not(stage0))] +impl Encodable for OwnedSlice { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.as_slice().encode(s) + } +} + +#[cfg(stage0)] impl, T: Decodable, E> Decodable for OwnedSlice { fn decode(d: &mut D) -> Result, E> { Ok(OwnedSlice::from_vec(match Decodable::decode(d) { @@ -96,3 +105,13 @@ impl, T: Decodable, E> Decodable for OwnedSlice { })) } } + +#[cfg(not(stage0))] +impl Decodable for OwnedSlice { + fn decode(d: &mut D) -> Result, D::Error> { + Ok(OwnedSlice::from_vec(match Decodable::decode(d) { + Ok(t) => t, + Err(e) => return Err(e) + })) + } +} diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 4bfcc94a083d4..b7e89b32b709e 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -653,6 +653,7 @@ impl<'a> PartialEq for &'a str { } } +#[cfg(stage0)] impl, E> Decodable for InternedString { fn decode(d: &mut D) -> Result { Ok(get_name(get_ident_interner().intern( @@ -660,12 +661,28 @@ impl, E> Decodable for InternedString { } } +#[cfg(not(stage0))] +impl Decodable for InternedString { + fn decode(d: &mut D) -> Result { + Ok(get_name(get_ident_interner().intern( + try!(d.read_str())[]))) + } +} + +#[cfg(stage0)] impl, E> Encodable for InternedString { fn encode(&self, s: &mut S) -> Result<(), E> { s.emit_str(self.string[]) } } +#[cfg(not(stage0))] +impl Encodable for InternedString { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(self.string[]) + } +} + /// Returns the string contents of a name, using the task-local interner. #[inline] pub fn get_name(name: ast::Name) -> InternedString { diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 6eee1d903ea64..13eda7bb88f05 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -111,14 +111,30 @@ impl> Hash for P { } } +#[cfg(stage0)] impl, T: 'static + Decodable> Decodable for P { fn decode(d: &mut D) -> Result, E> { Decodable::decode(d).map(P) } } +#[cfg(not(stage0))] +impl Decodable for P { + fn decode(d: &mut D) -> Result, D::Error> { + Decodable::decode(d).map(P) + } +} + +#[cfg(stage0)] impl, T: Encodable> Encodable for P { fn encode(&self, s: &mut S) -> Result<(), E> { (**self).encode(s) } } + +#[cfg(not(stage0))] +impl Encodable for P { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + (**self).encode(s) + } +} diff --git a/src/test/compile-fail/variance-trait-matching-2.rs b/src/test/compile-fail/variance-trait-matching-2.rs deleted file mode 100644 index cae7a4cefadb0..0000000000000 --- a/src/test/compile-fail/variance-trait-matching-2.rs +++ /dev/null @@ -1,30 +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. - -extern crate serialize; - -use std::fmt; -use serialize::{Encodable, Encoder}; - -pub fn buffer_encode<'a, - T:Encodable,fmt::Error>>( - to_encode_object: &T) - -> String { - let mut m = String::new(); - { - let mut encoder = - serialize::json::Encoder::new(&mut m); - //~^ ERROR `m` does not live long enough - to_encode_object.encode(&mut encoder); - } - m -} - -fn main() {} diff --git a/src/test/run-pass/issue-11881.rs b/src/test/run-pass/issue-11881.rs index 24deb7c2e4b40..d0d8a8589a4e2 100644 --- a/src/test/run-pass/issue-11881.rs +++ b/src/test/run-pass/issue-11881.rs @@ -40,16 +40,10 @@ enum WireProtocol { // ... } -fn encode_json< - T: for<'a> Encodable, - fmt::Error>>(val: &T, - wr: &mut SeekableMemWriter) { +fn encode_json(val: &T, wr: &mut SeekableMemWriter) { write!(wr, "{}", json::as_json(val)); } -fn encode_rbml<'a, - T: Encodable, - io::IoError>>(val: &T, - wr: &'a mut SeekableMemWriter) { +fn encode_rbml(val: &T, wr: &mut SeekableMemWriter) { let mut encoder = writer::Encoder::new(wr); val.encode(&mut encoder); } diff --git a/src/test/run-pass/issue-15924.rs b/src/test/run-pass/issue-15924.rs index 1ab8deda3830e..db9f1cc9df7c9 100644 --- a/src/test/run-pass/issue-15924.rs +++ b/src/test/run-pass/issue-15924.rs @@ -21,7 +21,7 @@ struct Foo { } #[unsafe_destructor] -impl Encodable, fmt::Error>> Drop for Foo { +impl Drop for Foo { fn drop(&mut self) { json::encode(&self.v); } diff --git a/src/test/run-pass/issue-4016.rs b/src/test/run-pass/issue-4016.rs index e5cc8414f064b..220332f63548a 100644 --- a/src/test/run-pass/issue-4016.rs +++ b/src/test/run-pass/issue-4016.rs @@ -13,7 +13,7 @@ extern crate serialize; use serialize::{json, Decodable}; -trait JD : Decodable { } +trait JD : Decodable {} fn exec() { let doc = json::from_str("").unwrap(); From acef2920d46350cbd9dc4f495072e3cc61bf7545 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 5 Jan 2015 00:27:48 -0800 Subject: [PATCH 29/29] Test fixes and rebase conflicts --- src/doc/guide-ownership.md | 6 ++-- src/libcollections/bit.rs | 4 +-- src/libcollections/dlist.rs | 1 + src/libcollections/str.rs | 4 +-- src/libcollections/string.rs | 18 ------------ src/libgraphviz/lib.rs | 2 +- src/librustc_trans/back/write.rs | 4 +-- src/librustc_trans/trans/base.rs | 2 +- src/librustc_typeck/check/_match.rs | 9 ++++-- src/librustc_typeck/check/callee.rs | 2 +- src/libstd/dynamic_lib.rs | 1 - src/libstd/io/process.rs | 11 +++---- src/libstd/sys/windows/backtrace.rs | 4 +-- src/libstd/sys/windows/fs.rs | 1 - src/libstd/sys/windows/pipe.rs | 19 +++++++----- src/libstd/sys/windows/process.rs | 31 ++++++++++---------- src/test/compile-fail/issue-17904.rs | 4 +-- src/test/compile-fail/macros-no-semicolon.rs | 2 +- src/test/run-pass/const-str-ptr.rs | 2 -- src/test/run-pass/issue-17904.rs | 2 ++ src/test/run-pass/running-with-no-runtime.rs | 4 ++- 21 files changed, 63 insertions(+), 70 deletions(-) diff --git a/src/doc/guide-ownership.md b/src/doc/guide-ownership.md index 883eb38aa381c..bdf589bbfe236 100644 --- a/src/doc/guide-ownership.md +++ b/src/doc/guide-ownership.md @@ -462,19 +462,19 @@ When talking about lifetime elision, we use the term 'input lifetime' and of a function, and an 'output lifetime' is a lifetime associated with the return value of a function. For example, this function has an input lifetime: -``` +```{rust,ignore} fn foo<'a>(bar: &'a str) ``` This one has an output lifetime: -``` +```{rust,ignore} fn foo<'a>() -> &'a str ``` This one has both: -``` +```{rust,ignore} fn foo<'a>(bar: &'a str) -> &'a str ``` diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 5e7089bb7aca2..7f40422bf6669 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -2541,7 +2541,7 @@ mod bitv_bench { for _ in range(0u, 100) { bitv |= 1 << ((r.next_u32() as uint) % u32::BITS); } - black_box(&bitv) + black_box(&bitv); }); } @@ -2553,7 +2553,7 @@ mod bitv_bench { for _ in range(0u, 100) { bitv.set((r.next_u32() as uint) % BENCH_BITS, true); } - black_box(&bitv) + black_box(&bitv); }); } diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index ca8e75ac43c8d..504d41f2df0e0 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -1064,6 +1064,7 @@ mod tests { } #[allow(deprecated)] + #[test] fn test_append() { { let mut m = DList::new(); diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index bae376c63fc98..26a26334ccb90 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -2828,7 +2828,7 @@ mod bench { let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; b.iter(|| { - for ch in s.chars() { black_box(ch) } + for ch in s.chars() { black_box(ch); } }); } @@ -2856,7 +2856,7 @@ mod bench { let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; b.iter(|| { - for ch in s.chars().rev() { black_box(ch) } + for ch in s.chars().rev() { black_box(ch); } }); } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index b98efc6272a05..11e6c48cfdbad 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1102,24 +1102,6 @@ mod tests { String::from_str("\u{FFFD}𐒋\u{FFFD}")); } - #[test] - fn test_from_buf_len() { - unsafe { - let a = vec![65u8, 65, 65, 65, 65, 65, 65, 0]; - assert_eq!(String::from_raw_buf_len(a.as_ptr(), 3), String::from_str("AAA")); - } - } - - #[test] - fn test_from_buf() { - unsafe { - let a = vec![65, 65, 65, 65, 65, 65, 65, 0]; - let b = a.as_ptr(); - let c = String::from_raw_buf(b); - assert_eq!(c, String::from_str("AAAAAAA")); - } - } - #[test] fn test_push_bytes() { let mut s = String::from_str("ABC"); diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index e3bcf70e8c82f..64cc490f4b163 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -587,7 +587,7 @@ pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N mod tests { use self::NodeLabels::*; use super::{Id, Labeller, Nodes, Edges, GraphWalk, render}; - use super::LabelText::{mod, LabelStr, EscStr}; + use super::LabelText::{self, LabelStr, EscStr}; use std::io::IoResult; use std::borrow::IntoCow; use std::iter::repeat; diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 089d7f737d3cf..98e2b4b9dddb5 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -22,7 +22,7 @@ use syntax::codemap; use syntax::diagnostic; use syntax::diagnostic::{Emitter, Handler, Level, mk_handler}; -use std::ffi::{mod, CString}; +use std::ffi::{self, CString}; use std::io::Command; use std::io::fs; use std::iter::Unfold; @@ -32,7 +32,7 @@ use std::mem; use std::sync::{Arc, Mutex}; use std::sync::mpsc::channel; use std::thread; -use libc::{mod, c_uint, c_int, c_void}; +use libc::{self, c_uint, c_int, c_void}; #[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] pub enum OutputType { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index d9c397d0c159e..d0324e2f86f98 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -88,7 +88,7 @@ use util::nodemap::NodeMap; use arena::TypedArena; use libc::{c_uint, uint64_t}; -use std::ffi::{mod, CString}; +use std::ffi::{self, CString}; use std::cell::{Cell, RefCell}; use std::collections::HashSet; use std::mem; diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 62cefd609564c..2b55aefc99999 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -195,8 +195,13 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ast::PatRegion(ref inner, mutbl) => { let inner_ty = fcx.infcx().next_ty_var(); - let mutbl = ty::deref(fcx.infcx().shallow_resolve(expected), true) - .map(|mt| mt.mutbl).unwrap_or(ast::MutImmutable); + // SNAP c894171 remove this `if`-`else` entirely after next snapshot + let mutbl = if mutbl == ast::MutImmutable { + ty::deref(fcx.infcx().shallow_resolve(expected), true) + .map(|mt| mt.mutbl).unwrap_or(ast::MutImmutable) + } else { + mutbl + }; let mt = ty::mt { ty: inner_ty, mutbl: mutbl }; let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 153c6463fbebb..0bc76e1baab84 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -22,7 +22,7 @@ use super::TupleArgumentsFlag; use super::write_call; use middle::infer; -use middle::ty::{mod, Ty}; +use middle::ty::{self, Ty}; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token; diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index afe8b3ef698f8..66cb1f2c948d9 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -271,7 +271,6 @@ pub mod dl { #[cfg(target_os = "windows")] pub mod dl { use iter::IteratorExt; - use iter::Iterator; use libc; use ops::FnOnce; use os; diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 8abae4d46af3c..ea232ad0c3f1b 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -35,6 +35,7 @@ use sys; use thread::Thread; #[cfg(windows)] use std::hash::sip::SipState; +#[cfg(windows)] use str; /// Signal a process to exit, without forcibly killing it. Corresponds to /// SIGTERM on unix platforms. @@ -109,11 +110,11 @@ struct EnvKey(CString); impl Hash for EnvKey { fn hash(&self, state: &mut SipState) { let &EnvKey(ref x) = self; - match x.as_str() { - Some(s) => for ch in s.chars() { + match str::from_utf8(x.as_bytes()) { + Ok(s) => for ch in s.chars() { (ch as u8 as char).to_lowercase().hash(state); }, - None => x.hash(state) + Err(..) => x.hash(state) } } } @@ -123,8 +124,8 @@ impl PartialEq for EnvKey { fn eq(&self, other: &EnvKey) -> bool { let &EnvKey(ref x) = self; let &EnvKey(ref y) = other; - match (x.as_str(), y.as_str()) { - (Some(xs), Some(ys)) => { + match (str::from_utf8(x.as_bytes()), str::from_utf8(y.as_bytes())) { + (Ok(xs), Ok(ys)) => { if xs.len() != ys.len() { return false } else { diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index e3b7413e37d37..4ccecfd1f5f2e 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -360,8 +360,8 @@ pub fn write(w: &mut Writer) -> IoResult<()> { let ptr = info.Name.as_ptr() as *const libc::c_char; let bytes = unsafe { ffi::c_str_to_bytes(&ptr) }; match str::from_utf8(bytes) { - Some(s) => try!(demangle(w, s)), - None => try!(w.write(bytes[..bytes.len()-1])), + Ok(s) => try!(demangle(w, s)), + Err(..) => try!(w.write(bytes[..bytes.len()-1])), } } try!(w.write(&['\n' as u8])); diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 9a94230065680..f8c75335b35dc 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -13,7 +13,6 @@ use alloc::arc::Arc; use libc::{self, c_int}; -use c_str::CString; use mem; use sys::os::fill_utf16_buf_and_decode; use path; diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index dcafb77e876fd..9996909f2f5bb 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -88,15 +88,20 @@ use prelude::v1::*; use libc; use ffi::CString; +use io::{self, IoError, IoResult}; use mem; use ptr; -use sync::{Arc, Mutex}; +use str; use sync::atomic::{AtomicBool, Ordering}; -use io::{self, IoError, IoResult}; +use sync::{Arc, Mutex}; use sys_common::{self, eof}; -use super::{c, os, timer, to_utf16, decode_error_detailed}; +use super::{c, os, timer, decode_error_detailed}; + +fn to_utf16(c: &CString) -> IoResult> { + super::to_utf16(str::from_utf8(c.as_bytes()).ok()) +} struct Event(libc::HANDLE); @@ -270,7 +275,7 @@ impl UnixStream { } pub fn connect(addr: &CString, timeout: Option) -> IoResult { - let addr = try!(to_utf16(addr.as_str())); + let addr = try!(to_utf16(addr)); let start = timer::now(); loop { match UnixStream::try_connect(addr.as_ptr()) { @@ -571,7 +576,7 @@ impl UnixListener { // 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 addr_v = try!(to_utf16(addr)); let ret = unsafe { pipe(addr_v.as_ptr(), true) }; if ret == libc::INVALID_HANDLE_VALUE { Err(super::last_error()) @@ -661,7 +666,7 @@ impl UnixAcceptor { // proceed in accepting new clients in the future if self.inner.closed.load(Ordering::SeqCst) { return Err(eof()) } - let name = try!(to_utf16(self.listener.name.as_str())); + let name = try!(to_utf16(&self.listener.name)); // Once we've got a "server handle", we need to wait for a client to // connect. The ConnectNamedPipe function will block this thread until @@ -753,7 +758,7 @@ impl UnixAcceptor { impl Clone for UnixAcceptor { fn clone(&self) -> UnixAcceptor { - let name = to_utf16(self.listener.name.as_str()).ok().unwrap(); + let name = to_utf16(&self.listener.name).ok().unwrap(); UnixAcceptor { inner: self.inner.clone(), event: Event::new(true, false).ok().unwrap(), diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index fc1fb7cacc650..9b3f2ca03736e 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,27 +10,26 @@ use prelude::v1::*; -use libc::{pid_t, c_void, c_int}; -use libc; +use collections; use ffi::CString; +use hash::Hash; +use io::fs::PathExtensions; +use io::process::{ProcessExit, ExitStatus, ExitSignal}; +use io::{IoResult, IoError}; use io; +use libc::{pid_t, c_void, c_int}; +use libc; use mem; use os; -use ptr; -use io::process::{ProcessExit, ExitStatus, ExitSignal}; -use collections; use path::BytesContainer; -use hash::Hash; -use io::{IoResult, IoError}; - +use ptr; +use str; +use sys::fs::FileDesc; use sys::fs; use sys::{self, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer}; -use sys::fs::FileDesc; use sys_common::helper_thread::Helper; use sys_common::{AsInner, mkerr_libc, timeout}; -use io::fs::PathExtensions; - pub use sys_common::ProcessConfig; /// A value representing a child process. @@ -142,10 +141,10 @@ impl Process { // 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()) + let path = path.join(cfg.program().as_bytes()) .with_extension(os::consts::EXE_EXTENSION); if path.exists() { - return Some(path.to_c_str()) + return Some(CString::from_slice(path.as_vec())) } } break @@ -363,11 +362,11 @@ fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMA fn make_command_line(prog: &CString, args: &[CString]) -> String { let mut cmd = String::new(); - append_arg(&mut cmd, prog.as_str() + append_arg(&mut cmd, str::from_utf8(prog.as_bytes()).ok() .expect("expected program name to be utf-8 encoded")); for arg in args.iter() { cmd.push(' '); - append_arg(&mut cmd, arg.as_str() + append_arg(&mut cmd, str::from_utf8(arg.as_bytes()).ok() .expect("expected argument to be utf-8 encoded")); } return cmd; @@ -449,7 +448,7 @@ fn with_dirp(d: Option<&CString>, cb: F) -> T where { match d { Some(dir) => { - let dir_str = dir.as_str() + let dir_str = str::from_utf8(dir.as_bytes()).ok() .expect("expected workingdirectory to be utf-8 encoded"); let mut dir_str: Vec = dir_str.utf16_units().collect(); dir_str.push(0); diff --git a/src/test/compile-fail/issue-17904.rs b/src/test/compile-fail/issue-17904.rs index 0ef4c78cd38ad..87bb0623c6ed0 100644 --- a/src/test/compile-fail/issue-17904.rs +++ b/src/test/compile-fail/issue-17904.rs @@ -11,7 +11,7 @@ struct Baz where U: Eq(U); // This is parsed as the new Fn* style parenthesis syntax. struct Baz where U: Eq(U) -> R; // Notice this parses as well. struct Baz(U) where U: Eq; // This rightfully signals no error as well. -struct Foo where T: Copy, (T); //^~ ERROR: unexpected token in `where` clause -struct Bar { x: T } where T: Copy //^~ ERROR: expected item, found `where` +struct Foo where T: Copy, (T); //~ ERROR: unexpected token in `where` clause +struct Bar { x: T } where T: Copy //~ ERROR: expected item, found `where` fn main() {} diff --git a/src/test/compile-fail/macros-no-semicolon.rs b/src/test/compile-fail/macros-no-semicolon.rs index fd5f5866f0940..0e85551e2161c 100644 --- a/src/test/compile-fail/macros-no-semicolon.rs +++ b/src/test/compile-fail/macros-no-semicolon.rs @@ -10,7 +10,7 @@ fn main() { assert!(1 == 2) - assert!(3 == 4) //~ ERROR expected one of `.`, `;`, or `}`, found `assert` + assert!(3 == 4) //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `assert` println!("hello"); } diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs index 1a84236793b4f..e846501be6ee5 100644 --- a/src/test/run-pass/const-str-ptr.rs +++ b/src/test/run-pass/const-str-ptr.rs @@ -18,8 +18,6 @@ pub fn main() { unsafe { let foo = &A as *const u8; assert_eq!(str::from_utf8_unchecked(&A), "hi"); - assert_eq!(String::from_raw_buf_len(foo, A.len()), "hi".to_string()); - assert_eq!(String::from_raw_buf_len(C, B.len()), "hi".to_string()); assert!(*C == A[0]); assert!(*(&B[0] as *const u8) == A[0]); } diff --git a/src/test/run-pass/issue-17904.rs b/src/test/run-pass/issue-17904.rs index 3ce347d67e3d9..d5e8de6a54a1b 100644 --- a/src/test/run-pass/issue-17904.rs +++ b/src/test/run-pass/issue-17904.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-pretty + struct Foo where T: Copy; struct Bar(T) where T: Copy; struct Bleh(T, U) where T: Copy, U: Sized; diff --git a/src/test/run-pass/running-with-no-runtime.rs b/src/test/run-pass/running-with-no-runtime.rs index fc53737bb445a..6f807fc34995e 100644 --- a/src/test/run-pass/running-with-no-runtime.rs +++ b/src/test/run-pass/running-with-no-runtime.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::ffi; use std::io::process::{Command, ProcessOutput}; use std::os; use std::rt::unwind::try; @@ -34,7 +35,8 @@ fn start(argc: int, argv: *const *const u8) -> int { let args = unsafe { range(0, argc as uint).map(|i| { - String::from_raw_buf(*argv.offset(i as int)).into_bytes() + let ptr = *argv.offset(i as int) as *const _; + ffi::c_str_to_bytes(&ptr).to_vec() }).collect::>() }; let me = args[0].as_slice();