diff --git a/mk/crates.mk b/mk/crates.mk index 93be1e6ba6326..6c4b983b40e85 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -29,6 +29,11 @@ # the HOST_CRATES set, but the HOST_CRATES set can depend on target # crates. # +# EXTERNAL_CRATES +# These crates are all imported using the git-subtree command and have a +# slightly different structure as they're primarily intended to be built +# with Cargo, but we build them manually here. +# # TOOLS # A list of all tools which will be built as part of the compilation # process. It is currently assumed that most tools are built through @@ -49,15 +54,16 @@ # automatically generated for all stage/host/target combinations. ################################################################################ -TARGET_CRATES := libc std flate arena term \ - serialize getopts collections test rand \ +TARGET_CRATES := libc std flate arena \ + collections test rand \ log graphviz core rbml alloc \ rustc_unicode rustc_bitflags RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros -CRATES := $(TARGET_CRATES) $(HOST_CRATES) +EXTERNAL_CRATES := term rustc_serialize getopts +CRATES := $(TARGET_CRATES) $(HOST_CRATES) $(EXTERNAL_CRATES) TOOLS := compiletest rustdoc rustc rustbook error-index-generator DEPS_core := @@ -68,37 +74,37 @@ DEPS_std := core libc rand alloc collections rustc_unicode \ native:rust_builtin native:backtrace native:rustrt_native \ rustc_bitflags DEPS_graphviz := std -DEPS_syntax := std term serialize log fmt_macros arena libc +DEPS_syntax := std term rustc_serialize log fmt_macros arena libc DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \ - rustc_typeck rustc_resolve log syntax serialize rustc_llvm \ + rustc_typeck rustc_resolve log syntax rustc_serialize rustc_llvm \ rustc_trans rustc_privacy rustc_lint DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ - log syntax serialize rustc_llvm + log syntax rustc_serialize rustc_llvm DEPS_rustc_typeck := rustc syntax DEPS_rustc_borrowck := rustc log graphviz syntax DEPS_rustc_resolve := rustc log syntax DEPS_rustc_privacy := rustc log syntax DEPS_rustc_lint := rustc log syntax -DEPS_rustc := syntax flate arena serialize getopts rbml \ +DEPS_rustc := syntax flate arena rustc_serialize getopts rbml \ log graphviz rustc_llvm rustc_back rustc_data_structures DEPS_rustc_llvm := native:rustllvm libc std DEPS_rustc_back := std syntax rustc_llvm flate log libc -DEPS_rustc_data_structures := std log serialize -DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \ +DEPS_rustc_data_structures := std log rustc_serialize +DEPS_rustdoc := rustc rustc_driver native:hoedown rustc_serialize getopts \ test rustc_lint DEPS_rustc_bitflags := core DEPS_flate := std native:miniz DEPS_arena := std DEPS_graphviz := std DEPS_glob := std -DEPS_serialize := std log -DEPS_rbml := std log serialize -DEPS_term := std log +DEPS_rustc_serialize := std +DEPS_rbml := std log rustc_serialize +DEPS_term := std DEPS_getopts := std DEPS_collections := core alloc rustc_unicode DEPS_num := std -DEPS_test := std getopts serialize rbml term native:rust_test_helpers +DEPS_test := std getopts rustc_serialize rbml term native:rust_test_helpers DEPS_rand := core DEPS_log := std DEPS_fmt_macros = std @@ -107,7 +113,7 @@ TOOL_DEPS_compiletest := test getopts TOOL_DEPS_rustdoc := rustdoc TOOL_DEPS_rustc := rustc_driver TOOL_DEPS_rustbook := std rustdoc -TOOL_DEPS_error-index-generator := rustdoc syntax serialize +TOOL_DEPS_error-index-generator := rustdoc syntax rustc_serialize TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs TOOL_SOURCE_rustc := $(S)src/driver/driver.rs @@ -136,11 +142,33 @@ DOC_CRATES := std alloc collections core libc rustc_unicode define RUST_CRATE CRATEFILE_$(1) := $$(S)src/lib$(1)/lib.rs RSINPUTS_$(1) := $$(call rwildcard,$(S)src/lib$(1)/,*.rs) +endef + +$(foreach crate,$(TARGET_CRATES),$(eval $(call RUST_CRATE,$(crate)))) +$(foreach crate,$(HOST_CRATES),$(eval $(call RUST_CRATE,$(crate)))) + +# Distinct from the above macro, this generates the variables needed for +# external crates (located in the src/external folder). These crates are +# typically intended to be built with Cargo so we need to pass some extra flags +# and use a different source location. +# +# $(1) is the crate to generate variables for +define EXTERNAL_CRATE +CRATEFILE_$(1) := $$(S)src/external/$(1)/src/lib.rs +RUSTFLAGS_$(1) += --crate-type rlib,dylib --crate-name $(1) --cfg rust_build +RSINPUTS_$(1) := $$(call rwildcard,$(S)src/external/$(1)/src/,*.rs) +endef + +$(foreach crate,$(EXTERNAL_CRATES),$(eval $(call EXTERNAL_CRATE,$(crate)))) + +# Build the dependencies array for all crates +# +# $(1) is the crate to generate variables for +define BUILD_CRATE_DEPS RUST_DEPS_$(1) := $$(filter-out native:%,$$(DEPS_$(1))) NATIVE_DEPS_$(1) := $$(patsubst native:%,%,$$(filter native:%,$$(DEPS_$(1)))) endef - -$(foreach crate,$(CRATES),$(eval $(call RUST_CRATE,$(crate)))) +$(foreach crate,$(CRATES),$(eval $(call BUILD_CRATE_DEPS,$(crate)))) # Similar to the macro above for crates, this macro is for tools # diff --git a/mk/dist.mk b/mk/dist.mk index 0fc9100b85b92..0ceb627dee300 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -53,7 +53,9 @@ PKG_FILES := \ driver \ etc \ error-index-generator \ - $(foreach crate,$(CRATES),lib$(crate)) \ + external \ + $(foreach crate,$(TARGET_CRATES),lib$(crate)) \ + $(foreach crate,$(HOST_CRATES),lib$(crate)) \ libcollectionstest \ libcoretest \ libbacktrace \ diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 9d575675cc8c9..d04a6720413fe 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -31,7 +31,6 @@ extern crate log; use std::env; use std::fs; use std::path::{Path, PathBuf}; -use getopts::{optopt, optflag, reqopt}; use common::Config; use common::{Pretty, DebugInfoGdb, DebugInfoLldb}; use util::logv; @@ -55,60 +54,60 @@ pub fn main() { run_tests(&config); } -pub fn parse_config(args: Vec ) -> Config { - - let groups : Vec = - vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"), - reqopt("", "run-lib-path", "path to target shared libraries", "PATH"), - reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"), - reqopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH"), - reqopt("", "python", "path to python to use for doc tests", "PATH"), - optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM"), - optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind"), - optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR"), - reqopt("", "src-base", "directory to scan for test files", "PATH"), - reqopt("", "build-base", "directory to deposit test outputs", "PATH"), - reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"), - reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"), - reqopt("", "mode", "which sort of compile tests to run", - "(compile-fail|parse-fail|run-fail|run-pass|run-pass-valgrind|pretty|debug-info)"), - optflag("", "ignored", "run tests marked as ignored"), - optopt("", "runtool", "supervisor program to run tests under \ - (eg. emulator, valgrind)", "PROGRAM"), - optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS"), - optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"), - optflag("", "verbose", "run tests verbosely, showing all output"), - optopt("", "logfile", "file to log test execution to", "FILE"), - optflag("", "jit", "run tests under the JIT"), - optopt("", "target", "the target to build for", "TARGET"), - optopt("", "host", "the host to build for", "HOST"), - optopt("", "gdb-version", "the version of GDB used", "VERSION STRING"), - optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING"), - optopt("", "android-cross-path", "Android NDK standalone path", "PATH"), - optopt("", "adb-path", "path to the android debugger", "PATH"), - optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"), - optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH"), - optflag("h", "help", "show this message")); +pub fn parse_config(args: Vec) -> Config { + + let mut options = getopts::Options::new(); + options + .reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") + .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") + .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") + .reqopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") + .reqopt("", "python", "path to python to use for doc tests", "PATH") + .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM") + .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") + .optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR") + .reqopt("", "src-base", "directory to scan for test files", "PATH") + .reqopt("", "build-base", "directory to deposit test outputs", "PATH") + .reqopt("", "aux-base", "directory to find auxiliary test files", "PATH") + .reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET") + .reqopt("", "mode", "which sort of compile tests to run", + "(compile-fail|parse-fail|run-fail|run-pass|run-pass-valgrind|pretty|debug-info)") + .optflag("", "ignored", "run tests marked as ignored") + .optopt("", "runtool", "supervisor program to run tests under \ + (eg. emulator, valgrind)", "PROGRAM") + .optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS") + .optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS") + .optflag("", "verbose", "run tests verbosely, showing all output") + .optopt("", "logfile", "file to log test execution to", "FILE") + .optflag("", "jit", "run tests under the JIT") + .optopt("", "target", "the target to build for", "TARGET") + .optopt("", "host", "the host to build for", "HOST") + .optopt("", "gdb-version", "the version of GDB used", "VERSION STRING") + .optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING") + .optopt("", "android-cross-path", "Android NDK standalone path", "PATH") + .optopt("", "adb-path", "path to the android debugger", "PATH") + .optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH") + .optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH") + .optflag("h", "help", "show this message"); assert!(!args.is_empty()); let argv0 = args[0].clone(); let args_ = args.tail(); if args[1] == "-h" || args[1] == "--help" { let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - println!("{}", getopts::usage(&message, &groups)); + println!("{}", options.usage(&message)); println!(""); panic!() } - let matches = - &match getopts::getopts(args_, &groups) { - Ok(m) => m, - Err(f) => panic!("{:?}", f) - }; + let matches = &match options.parse(args_) { + Ok(m) => m, + Err(f) => panic!("{:?}", f) + }; if matches.opt_present("h") || matches.opt_present("help") { let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - println!("{}", getopts::usage(&message, &groups)); + println!("{}", options.usage(&message)); println!(""); panic!() } diff --git a/src/etc/tidy.py b/src/etc/tidy.py index 9f5f919bce8d8..8fbaa2e0bf0d0 100644 --- a/src/etc/tidy.py +++ b/src/etc/tidy.py @@ -108,6 +108,7 @@ def interesting_file(f): 'src/rustllvm', 'src/rt/valgrind', 'src/rt/msvc', + 'src/external', 'src/rust-installer' } diff --git a/src/external/README.md b/src/external/README.md new file mode 100644 index 0000000000000..48913687644e6 --- /dev/null +++ b/src/external/README.md @@ -0,0 +1,42 @@ +## External crates + +All crates in this directory are hosted externally from this repository and are +imported via the standard `git-subtree` command. These crates **should not** be +edited directly, but instead changes to should go upstream and then be pulled +into these crates. + +Crates here are listed in the `EXTERNAL_CRATES` array in `mk/crates.mk` and are +built via the standard build system. + +### Adding a new external crate + +1. Make sure the crate has the appropriate `#![cfg_attr]` annotations to make + the crate unstable in the distribution with a message pointing to crates.io. + See the existing crates in the `src/external` folder for examples. + +2. To add a new crate `foo` to this folder, first execute the following: + + ```sh + git subtree add -P src/external/foo https://github.com/bar/foo master --squash + ``` + + This will check out the crate into this folder, squashing the entire history + into one commit (the rust-lang/rust repo doesn't need the whole history of the + crate). + +3. Next, edit `mk/crates.mk` appropriately by modifying `EXTERNAL_CRATES` and + possibly some other crates and/or dependency lists. + +4. Add the crate to `src/test/compile-fail-fulldeps/unstable-crates.rs` to + ensure that it is unstable in the distribution. + +### Updating an external crate + +To pull in upstream changes to a library `foo`, execute the following + +```sh +git subtree pull -P src/external/foo https://github.com/bar/foo master --squash +``` + +Similar to the addition process the `--squash` argument is provided to squash +all changes into one commit. diff --git a/src/external/getopts/.gitignore b/src/external/getopts/.gitignore new file mode 100644 index 0000000000000..4fffb2f89cbd8 --- /dev/null +++ b/src/external/getopts/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/src/external/getopts/.travis.yml b/src/external/getopts/.travis.yml new file mode 100644 index 0000000000000..01859cab7657e --- /dev/null +++ b/src/external/getopts/.travis.yml @@ -0,0 +1,24 @@ +language: rust +rust: + - 1.0.0 + - beta + - nightly +script: + - cargo build --verbose + - cargo test --verbose + - cargo doc +after_success: | + [ $TRAVIS_BRANCH = master ] && + [ $TRAVIS_PULL_REQUEST = false ] && + [ $TRAVIS_RUST_VERSION = nightly ] && + echo '' > target/doc/index.html && + sudo pip install ghp-import && + ghp-import -n target/doc && + git push -fq https://${TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages + +env: + global: + secure: H6SBXFQ/i/xRTCkEgKwk9WTSKXXaaEMqrASLbzKqhqJHR3ed/vp5YBWzlCJkAI3+2j3iVmbCfHqtpzmF9f1GAn+apg3mDI5GfFRJAfncHhZoN332wcBLvvNuRvJS9wRk3j3kOLKjBJmPa7+TCFafyXfCAutzfUlQPK8dgxG8WEI= +notifications: + email: + on_success: never diff --git a/src/external/getopts/Cargo.toml b/src/external/getopts/Cargo.toml new file mode 100644 index 0000000000000..f792419dc59c6 --- /dev/null +++ b/src/external/getopts/Cargo.toml @@ -0,0 +1,16 @@ +[package] + +name = "getopts" +version = "0.2.11" +authors = ["The Rust Project Developers"] +license = "MIT/Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-lang/getopts" +documentation = "http://doc.rust-lang.org/getopts" +homepage = "https://github.com/rust-lang/getopts" +description = """ +getopts-like option parsing. +""" + +[dependencies] +log = "0.3" diff --git a/src/external/getopts/LICENSE-APACHE b/src/external/getopts/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/src/external/getopts/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/external/getopts/LICENSE-MIT b/src/external/getopts/LICENSE-MIT new file mode 100644 index 0000000000000..39d4bdb5acd31 --- /dev/null +++ b/src/external/getopts/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/external/getopts/README.md b/src/external/getopts/README.md new file mode 100644 index 0000000000000..c19f48fb06b5c --- /dev/null +++ b/src/external/getopts/README.md @@ -0,0 +1,23 @@ +getopts +=== + +A Rust library for option parsing for CLI utilities. + +[![Build Status](https://travis-ci.org/rust-lang/getopts.svg?branch=master)](https://travis-ci.org/rust-lang/getopts) + +[Documentation](http://doc.rust-lang.org/getopts) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +getopts = "0.2.4" +``` + +and this to your crate root: + +```rust +extern crate getopts; +``` diff --git a/src/libgetopts/lib.rs b/src/external/getopts/src/lib.rs similarity index 50% rename from src/libgetopts/lib.rs rename to src/external/getopts/src/lib.rs index 48649a3143464..1fd68973b08e1 100644 --- a/src/libgetopts/lib.rs +++ b/src/external/getopts/src/lib.rs @@ -7,15 +7,18 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// +// ignore-lexer-test FIXME #15677 //! Simple getopt alternative. //! -//! Construct a vector of options, either by using `reqopt`, `optopt`, and `optflag` -//! or by building them from components yourself, and pass them to `getopts`, -//! along with a vector of actual arguments (not including `argv[0]`). You'll -//! either get a failure code back, or a match. You'll have to verify whether -//! the amount of 'free' arguments in the match is what you expect. Use `opt_*` -//! accessors to get argument values out of the matches object. +//! Construct a vector of options, either by using `reqopt`, `optopt`, and +//! `optflag` or by building them from components yourself, and pass them to +//! `getopts`, along with a vector of actual arguments (not including +//! `argv[0]`). You'll either get a failure code back, or a match. You'll have +//! to verify whether the amount of 'free' arguments in the match is what you +//! expect. Use `opt_*` accessors to get argument values out of the matches +//! object. //! //! Single-character options are expected to appear on the command line with a //! single preceding dash; multiple-character options are expected to be @@ -23,16 +26,32 @@ //! argument following either a space or an equals sign. Single-character //! options don't require the space. //! +//! # Usage +//! +//! This crate is [on crates.io](https://crates.io/crates/getopts) and can be +//! used by adding `getopts` to the dependencies in your project's `Cargo.toml`. +//! +//! ```toml +//! [dependencies] +//! getopts = "0.2" +//! ``` +//! +//! and this to your crate root: +//! +//! ```rust +//! extern crate getopts; +//! ``` +//! //! # Example //! //! The following example shows simple command line parsing for an application -//! that requires an input file to be specified, accepts an optional output -//! file name following `-o`, and accepts both `-h` and `--help` as optional flags. +//! that requires an input file to be specified, accepts an optional output file +//! name following `-o`, and accepts both `-h` and `--help` as optional flags. //! //! ```{.rust} //! extern crate getopts; -//! use getopts::{optopt,optflag,getopts,OptGroup,usage}; -//! use std::os; +//! use getopts::Options; +//! use std::env; //! //! fn do_work(inp: &str, out: Option) { //! println!("{}", inp); @@ -42,57 +61,47 @@ //! } //! } //! -//! fn print_usage(program: &str, opts: &[OptGroup]) { +//! fn print_usage(program: &str, opts: Options) { //! let brief = format!("Usage: {} [options]", program); -//! print!("{}", usage(brief, opts)); +//! print!("{}", opts.usage(&brief)); //! } //! //! fn main() { -//! let args: Vec = os::args(); -//! +//! let args: Vec = env::args().collect(); //! let program = args[0].clone(); //! -//! let opts = &[ -//! optopt("o", "", "set output file name", "NAME"), -//! optflag("h", "help", "print this help menu") -//! ]; -//! let matches = match getopts(args.tail(), opts) { +//! let mut opts = Options::new(); +//! opts.optopt("o", "", "set output file name", "NAME"); +//! opts.optflag("h", "help", "print this help menu"); +//! let matches = match opts.parse(&args[1..]) { //! Ok(m) => { m } //! Err(f) => { panic!(f.to_string()) } //! }; //! if matches.opt_present("h") { -//! print_usage(program, opts); +//! print_usage(&program, opts); //! return; //! } //! let output = matches.opt_str("o"); //! let input = if !matches.free.is_empty() { //! matches.free[0].clone() //! } else { -//! print_usage(program, opts); +//! print_usage(&program, opts); //! return; //! }; -//! do_work(input, output); +//! do_work(&input, output); //! } //! ``` - -// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) -#![cfg_attr(stage0, feature(custom_attribute))] -#![crate_name = "getopts"] -#![unstable(feature = "rustc_private", - reason = "use the crates.io `getopts` library instead")] -#![staged_api] -#![crate_type = "rlib"] -#![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "http://doc.rust-lang.org/nightly/", - html_playground_url = "http://play.rust-lang.org/")] - + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/getopts/")] #![deny(missing_docs)] -#![feature(staged_api)] -#![feature(str_char)] -#![cfg_attr(test, feature(rustc_private))] +#![cfg_attr(test, deny(warnings))] +#![cfg_attr(rust_build, feature(staged_api))] +#![cfg_attr(rust_build, staged_api)] +#![cfg_attr(rust_build, + unstable(feature = "rustc_private", + reason = "use the crates.io `getopts` library instead"))] #[cfg(test)] #[macro_use] extern crate log; @@ -105,13 +114,435 @@ use self::SplitWithinState::*; use self::Whitespace::*; use self::LengthLimit::*; +use std::ffi::OsStr; use std::fmt; -use std::iter::repeat; +use std::iter::{repeat, IntoIterator}; use std::result; +/// A description of the options that a program can handle +pub struct Options { + grps: Vec, + parsing_style : ParsingStyle +} + +impl Options { + /// Create a blank set of options + pub fn new() -> Options { + Options { + grps: Vec::new(), + parsing_style: ParsingStyle::FloatingFrees + } + } + + /// Set the parsing style + pub fn parsing_style(&mut self, style: ParsingStyle) -> &mut Options { + self.parsing_style = style; + self + } + + /// Create a generic option group, stating all parameters explicitly + pub fn opt(&mut self, short_name: &str, long_name: &str, desc: &str, + hint: &str, hasarg: HasArg, occur: Occur) -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: hint.to_string(), + desc: desc.to_string(), + hasarg: hasarg, + occur: occur + }); + self + } + + /// Create a long option that is optional and does not take an argument. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + pub fn optflag(&mut self, short_name: &str, long_name: &str, desc: &str) + -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: "".to_string(), + desc: desc.to_string(), + hasarg: No, + occur: Optional + }); + self + } + + /// Create a long option that can occur more than once and does not + /// take an argument. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + pub fn optflagmulti(&mut self, short_name: &str, long_name: &str, desc: &str) + -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: "".to_string(), + desc: desc.to_string(), + hasarg: No, + occur: Multi + }); + self + } + + /// Create a long option that is optional and takes an optional argument. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + /// * `hint` - Hint that is used in place of the argument in the usage help, + /// e.g. `"FILE"` for a `-o FILE` option + pub fn optflagopt(&mut self, short_name: &str, long_name: &str, desc: &str, + hint: &str) -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: hint.to_string(), + desc: desc.to_string(), + hasarg: Maybe, + occur: Optional + }); + self + } + + /// Create a long option that is optional, takes an argument, and may occur + /// multiple times. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + /// * `hint` - Hint that is used in place of the argument in the usage help, + /// e.g. `"FILE"` for a `-o FILE` option + pub fn optmulti(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) + -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: hint.to_string(), + desc: desc.to_string(), + hasarg: Yes, + occur: Multi + }); + self + } + + /// Create a long option that is optional and takes an argument. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + /// * `hint` - Hint that is used in place of the argument in the usage help, + /// e.g. `"FILE"` for a `-o FILE` option + pub fn optopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) + -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: hint.to_string(), + desc: desc.to_string(), + hasarg: Yes, + occur: Optional + }); + self + } + + /// Create a long option that is required and takes an argument. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + /// * `hint` - Hint that is used in place of the argument in the usage help, + /// e.g. `"FILE"` for a `-o FILE` option + pub fn reqopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) + -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: hint.to_string(), + desc: desc.to_string(), + hasarg: Yes, + occur: Req + }); + self + } + + /// Parse command line arguments according to the provided options. + /// + /// On success returns `Ok(Matches)`. Use methods such as `opt_present` + /// `opt_str`, etc. to interrogate results. + /// # Panics + /// + /// Returns `Err(Fail)` on failure: use the `Debug` implementation of `Fail` + /// to display information about it. + pub fn parse(&self, args: C) -> Result + where C::Item: AsRef + { + let opts: Vec = self.grps.iter().map(|x| x.long_to_short()).collect(); + let n_opts = opts.len(); + + fn f(_x: usize) -> Vec { return Vec::new(); } + + let mut vals = (0 .. n_opts).map(f).collect::>(); + let mut free: Vec = Vec::new(); + let args = args.into_iter().map(|i| { + i.as_ref().to_str().unwrap().to_string() + }).collect::>(); + let l = args.len(); + let mut i = 0; + while i < l { + let cur = args[i].clone(); + let curlen = cur.len(); + if !is_arg(&cur) { + match self.parsing_style { + ParsingStyle::FloatingFrees => free.push(cur), + ParsingStyle::StopAtFirstFree => { + while i < l { + free.push(args[i].clone()); + i += 1; + } + break; + } + } + } else if cur == "--" { + let mut j = i + 1; + while j < l { free.push(args[j].clone()); j += 1; } + break; + } else if cur == "-" { + free.push(cur); + } else { + let mut names; + let mut i_arg = None; + if cur.as_bytes()[1] == b'-' { + let tail = &cur[2..curlen]; + let tail_eq: Vec<&str> = tail.split('=').collect(); + if tail_eq.len() <= 1 { + names = vec!(Long(tail.to_string())); + } else { + names = + vec!(Long(tail_eq[0].to_string())); + i_arg = Some(tail_eq[1].to_string()); + } + } else { + names = Vec::new(); + for (j, ch) in cur.char_indices().skip(1) { + let opt = Short(ch); + + /* In a series of potential options (eg. -aheJ), if we + see one which takes an argument, we assume all + subsequent characters make up the argument. This + allows options such as -L/usr/local/lib/foo to be + interpreted correctly + */ + + let opt_id = match find_opt(&opts, opt.clone()) { + Some(id) => id, + None => return Err(UnrecognizedOption(opt.to_string())) + }; + + names.push(opt); + + let arg_follows = match opts[opt_id].hasarg { + Yes | Maybe => true, + No => false + }; + + if arg_follows { + let next = j + ch.len_utf8(); + if next < cur.len() { + i_arg = Some(cur[next..curlen].to_string()); + break; + } + } + } + } + let mut name_pos = 0; + for nm in names.iter() { + name_pos += 1; + let optid = match find_opt(&opts, (*nm).clone()) { + Some(id) => id, + None => return Err(UnrecognizedOption(nm.to_string())) + }; + match opts[optid].hasarg { + No => { + if name_pos == names.len() && !i_arg.is_none() { + return Err(UnexpectedArgument(nm.to_string())); + } + vals[optid].push(Given); + } + Maybe => { + if !i_arg.is_none() { + vals[optid] + .push(Val((i_arg.clone()) + .unwrap())); + } else if name_pos < names.len() || i + 1 == l || + is_arg(&args[i + 1]) { + vals[optid].push(Given); + } else { + i += 1; + vals[optid].push(Val(args[i].clone())); + } + } + Yes => { + if !i_arg.is_none() { + vals[optid].push(Val(i_arg.clone().unwrap())); + } else if i + 1 == l { + return Err(ArgumentMissing(nm.to_string())); + } else { + i += 1; + vals[optid].push(Val(args[i].clone())); + } + } + } + } + } + i += 1; + } + for i in 0 .. n_opts { + let n = vals[i].len(); + let occ = opts[i].occur; + if occ == Req && n == 0 { + return Err(OptionMissing(opts[i].name.to_string())); + } + if occ != Multi && n > 1 { + return Err(OptionDuplicated(opts[i].name.to_string())); + } + } + Ok(Matches { + opts: opts, + vals: vals, + free: free + }) + } + + /// Derive a short one-line usage summary from a set of long options. + pub fn short_usage(&self, program_name: &str) -> String { + let mut line = format!("Usage: {} ", program_name); + line.push_str(&self.grps.iter() + .map(format_option) + .collect::>() + .connect(" ")); + line + } + + /// Derive a usage message from a set of long options. + pub fn usage(&self, brief: &str) -> String { + let desc_sep = format!("\n{}", repeat(" ").take(24).collect::()); + + let rows = self.grps.iter().map(|optref| { + let OptGroup{short_name, + long_name, + hint, + desc, + hasarg, + ..} = (*optref).clone(); + + let mut row = " ".to_string(); + + // short option + match short_name.len() { + 0 => {} + 1 => { + row.push('-'); + row.push_str(&short_name); + row.push(' '); + } + _ => panic!("the short name should only be 1 ascii char long"), + } + + // long option + match long_name.len() { + 0 => {} + _ => { + row.push_str("--"); + row.push_str(&long_name); + row.push(' '); + } + } + + // arg + match hasarg { + No => {} + Yes => row.push_str(&hint), + Maybe => { + row.push('['); + row.push_str(&hint); + row.push(']'); + } + } + + // FIXME: #5516 should be graphemes not codepoints + // here we just need to indent the start of the description + let rowlen = row.chars().count(); + if rowlen < 24 { + for _ in 0 .. 24 - rowlen { + row.push(' '); + } + } else { + row.push_str(&desc_sep) + } + + // Normalize desc to contain words separated by one space character + let mut desc_normalized_whitespace = String::new(); + for word in desc.split(|c: char| c.is_whitespace()) + .filter(|s| !s.is_empty()) { + desc_normalized_whitespace.push_str(word); + desc_normalized_whitespace.push(' '); + } + + // FIXME: #5516 should be graphemes not codepoints + let mut desc_rows = Vec::new(); + each_split_within(&desc_normalized_whitespace, + 54, + |substr| { + desc_rows.push(substr.to_string()); + true + }); + + // FIXME: #5516 should be graphemes not codepoints + // wrapped description + row.push_str(&desc_rows.connect(&desc_sep)); + + row + }); + + format!("{}\n\nOptions:\n{}\n", brief, + rows.collect::>().connect("\n")) + } +} + +/// What parsing style to use when parsing arguments +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum ParsingStyle { + /// Flags and "free" arguments can be freely inter-mixed. + FloatingFrees, + /// As soon as a "free" argument (i.e. non-flag) is encountered, stop + /// considering any remaining arguments as flags. + StopAtFirstFree +} + /// Name of an option. Either a string or a single char. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum Name { +#[derive(Clone, PartialEq, Eq)] +enum Name { /// A string representing the long name of an option. /// For example: "help" Long(String), @@ -121,7 +552,7 @@ pub enum Name { } /// Describes whether an option has an argument. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum HasArg { /// The option requires an argument. Yes, @@ -132,7 +563,7 @@ pub enum HasArg { } /// Describes how often an option may occur. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum Occur { /// The option occurs once. Req, @@ -143,38 +574,38 @@ pub enum Occur { } /// A description of a possible option. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct Opt { +#[derive(Clone, PartialEq, Eq)] +struct Opt { /// Name of the option - pub name: Name, + name: Name, /// Whether it has an argument - pub hasarg: HasArg, + hasarg: HasArg, /// How often it can occur - pub occur: Occur, + occur: Occur, /// Which options it aliases - pub aliases: Vec, + aliases: Vec, } /// One group of options, e.g., both `-h` and `--help`, along with /// their shared description and properties. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct OptGroup { +#[derive(Clone, PartialEq, Eq)] +struct OptGroup { /// Short name of the option, e.g. `h` for a `-h` option - pub short_name: String, + short_name: String, /// Long name of the option, e.g. `help` for a `--help` option - pub long_name: String, + long_name: String, /// Hint for argument, e.g. `FILE` for a `-o FILE` option - pub hint: String, + hint: String, /// Description for usage help text - pub desc: String, + desc: String, /// Whether option has an argument - pub hasarg: HasArg, + hasarg: HasArg, /// How often it can occur - pub occur: Occur + occur: Occur } /// Describes whether an option is given at all or has a value. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq)] enum Optval { Val(String), Given, @@ -182,7 +613,7 @@ enum Optval { /// The result of checking command line arguments. Contains a vector /// of matches and a vector of free strings. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq)] pub struct Matches { /// Options that matched opts: Vec, @@ -195,7 +626,7 @@ pub struct Matches { /// The type returned when the command line does not conform to the /// expected format. Use the `Debug` implementation to output detailed /// information. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum Fail { /// The option requires an argument but none was passed. ArgumentMissing(String), @@ -210,7 +641,7 @@ pub enum Fail { } /// The type of failure that occurred. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq)] #[allow(missing_docs)] pub enum FailType { ArgumentMissing_, @@ -226,7 +657,7 @@ pub type Result = result::Result; impl Name { fn from_str(nm: &str) -> Name { if nm.len() == 1 { - Short(nm.char_at(0)) + Short(nm.as_bytes()[0] as char) } else { Long(nm.to_string()) } @@ -243,7 +674,7 @@ impl Name { impl OptGroup { /// Translate OptGroup into Opt. /// (Both short and long names correspond to different Opts). - pub fn long_to_short(&self) -> Opt { + fn long_to_short(&self) -> Opt { let OptGroup { short_name, long_name, @@ -261,7 +692,7 @@ impl OptGroup { aliases: Vec::new() }, (1,0) => Opt { - name: Short(short_name.char_at(0)), + name: Short(short_name.as_bytes()[0] as char), hasarg: hasarg, occur: occur, aliases: Vec::new() @@ -272,7 +703,7 @@ impl OptGroup { occur: occur, aliases: vec!( Opt { - name: Short(short_name.char_at(0)), + name: Short(short_name.as_bytes()[0] as char), hasarg: hasarg, occur: occur, aliases: Vec::new() @@ -286,19 +717,14 @@ impl OptGroup { impl Matches { fn opt_vals(&self, nm: &str) -> Vec { - match find_opt(&self.opts[..], Name::from_str(nm)) { + match find_opt(&self.opts, Name::from_str(nm)) { Some(id) => self.vals[id].clone(), None => panic!("No option '{}' defined", nm) } } fn opt_val(&self, nm: &str) -> Option { - let vals = self.opt_vals(nm); - if vals.is_empty() { - None - } else { - Some(vals[0].clone()) - } + self.opt_vals(nm).into_iter().next() } /// Returns true if an option was matched. @@ -313,24 +739,22 @@ impl Matches { /// Returns true if any of several options were matched. pub fn opts_present(&self, names: &[String]) -> bool { - for nm in names { - match find_opt(&self.opts, Name::from_str(&**nm)) { - Some(id) if !self.vals[id].is_empty() => return true, - _ => (), - }; - } - false + names.iter().any(|nm| { + match find_opt(&self.opts, Name::from_str(&nm)) { + Some(id) if !self.vals[id].is_empty() => true, + _ => false, + } + }) } /// Returns the string argument supplied to one of several matching options or `None`. pub fn opts_str(&self, names: &[String]) -> Option { - for nm in names { - match self.opt_val(&nm[..]) { - Some(Val(ref s)) => return Some(s.clone()), - _ => () + names.iter().filter_map(|nm| { + match self.opt_val(&nm) { + Some(Val(s)) => Some(s), + _ => None, } - } - None + }).next() } /// Returns a vector of the arguments provided to all matches of the given @@ -338,26 +762,19 @@ impl Matches { /// /// Used when an option accepts multiple values. pub fn opt_strs(&self, nm: &str) -> Vec { - let mut acc: Vec = Vec::new(); - let r = self.opt_vals(nm); - for v in &r { - match *v { - Val(ref s) => acc.push((*s).clone()), - _ => () + self.opt_vals(nm).into_iter().filter_map(|v| { + match v { + Val(s) => Some(s), + _ => None, } - } - acc + }).collect() } /// Returns the string argument supplied to a matching option or `None`. pub fn opt_str(&self, nm: &str) -> Option { - let vals = self.opt_vals(nm); - if vals.is_empty() { - return None::; - } - match vals[0] { - Val(ref s) => Some((*s).clone()), - _ => None + match self.opt_val(nm) { + Some(Val(s)) => Some(s), + _ => None, } } @@ -368,21 +785,17 @@ impl Matches { /// present but no argument was provided, and the argument if the option was /// present and an argument was provided. pub fn opt_default(&self, nm: &str, def: &str) -> Option { - let vals = self.opt_vals(nm); - if vals.is_empty() { - None - } else { - match vals[0] { - Val(ref s) => Some((*s).clone()), - _ => Some(def.to_string()) - } + match self.opt_val(nm) { + Some(Val(s)) => Some(s), + Some(_) => Some(def.to_string()), + None => None, } } } fn is_arg(arg: &str) -> bool { - arg.len() > 1 && arg.as_bytes()[0] == b'-' + arg.as_bytes().get(0) == Some(&b'-') } fn find_opt(opts: &[Opt], nm: Name) -> Option { @@ -393,7 +806,7 @@ fn find_opt(opts: &[Opt], nm: Name) -> Option { } // Search in aliases. - for candidate in opts { + for candidate in opts.iter() { if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() { return opts.iter().position(|opt| opt.name == candidate.name); } @@ -402,153 +815,6 @@ fn find_opt(opts: &[Opt], nm: Name) -> Option { None } -/// Create a long option that is required and takes an argument. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -/// * `hint` - Hint that is used in place of the argument in the usage help, -/// e.g. `"FILE"` for a `-o FILE` option -pub fn reqopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_string(), - long_name: long_name.to_string(), - hint: hint.to_string(), - desc: desc.to_string(), - hasarg: Yes, - occur: Req - } -} - -/// Create a long option that is optional and takes an argument. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -/// * `hint` - Hint that is used in place of the argument in the usage help, -/// e.g. `"FILE"` for a `-o FILE` option -pub fn optopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_string(), - long_name: long_name.to_string(), - hint: hint.to_string(), - desc: desc.to_string(), - hasarg: Yes, - occur: Optional - } -} - -/// Create a long option that is optional and does not take an argument. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -pub fn optflag(short_name: &str, long_name: &str, desc: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_string(), - long_name: long_name.to_string(), - hint: "".to_string(), - desc: desc.to_string(), - hasarg: No, - occur: Optional - } -} - -/// Create a long option that can occur more than once and does not -/// take an argument. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -pub fn optflagmulti(short_name: &str, long_name: &str, desc: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_string(), - long_name: long_name.to_string(), - hint: "".to_string(), - desc: desc.to_string(), - hasarg: No, - occur: Multi - } -} - -/// Create a long option that is optional and takes an optional argument. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -/// * `hint` - Hint that is used in place of the argument in the usage help, -/// e.g. `"FILE"` for a `-o FILE` option -pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_string(), - long_name: long_name.to_string(), - hint: hint.to_string(), - desc: desc.to_string(), - hasarg: Maybe, - occur: Optional - } -} - -/// Create a long option that is optional, takes an argument, and may occur -/// multiple times. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -/// * `hint` - Hint that is used in place of the argument in the usage help, -/// e.g. `"FILE"` for a `-o FILE` option -pub fn optmulti(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_string(), - long_name: long_name.to_string(), - hint: hint.to_string(), - desc: desc.to_string(), - hasarg: Yes, - occur: Multi - } -} - -/// Create a generic option group, stating all parameters explicitly -pub fn opt(short_name: &str, - long_name: &str, - desc: &str, - hint: &str, - hasarg: HasArg, - occur: Occur) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_string(), - long_name: long_name.to_string(), - hint: hint.to_string(), - desc: desc.to_string(), - hasarg: hasarg, - occur: occur - } -} - -impl Fail { - /// Convert a `Fail` enum into an error string. - #[unstable(feature = "rustc_private")] - #[deprecated(since = "1.0.0", - reason = "use `fmt::Display` (`{}` format specifier)")] - pub fn to_err_msg(self) -> String { - self.to_string() - } -} - impl fmt::Display for Fail { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -571,228 +837,6 @@ impl fmt::Display for Fail { } } -/// Parse command line arguments according to the provided options. -/// -/// On success returns `Ok(Matches)`. Use methods such as `opt_present` -/// `opt_str`, etc. to interrogate results. -/// # Panics -/// -/// Returns `Err(Fail)` on failure: use the `Debug` implementation of `Fail` to display -/// information about it. -pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result { - let opts: Vec = optgrps.iter().map(|x| x.long_to_short()).collect(); - let n_opts = opts.len(); - - fn f(_x: usize) -> Vec { return Vec::new(); } - - let mut vals: Vec<_> = (0..n_opts).map(f).collect(); - let mut free: Vec = Vec::new(); - let l = args.len(); - let mut i = 0; - while i < l { - let cur = args[i].clone(); - let curlen = cur.len(); - if !is_arg(&cur[..]) { - free.push(cur); - } else if cur == "--" { - let mut j = i + 1; - while j < l { free.push(args[j].clone()); j += 1; } - break; - } else { - let mut names; - let mut i_arg = None; - if cur.as_bytes()[1] == b'-' { - let tail = &cur[2..curlen]; - let tail_eq: Vec<&str> = tail.split('=').collect(); - if tail_eq.len() <= 1 { - names = vec!(Long(tail.to_string())); - } else { - names = - vec!(Long(tail_eq[0].to_string())); - i_arg = Some(tail_eq[1].to_string()); - } - } else { - let mut j = 1; - names = Vec::new(); - while j < curlen { - let ch = cur.char_at(j); - let opt = Short(ch); - - /* In a series of potential options (eg. -aheJ), if we - see one which takes an argument, we assume all - subsequent characters make up the argument. This - allows options such as -L/usr/local/lib/foo to be - interpreted correctly - */ - - let opt_id = match find_opt(&opts, opt.clone()) { - Some(id) => id, - None => return Err(UnrecognizedOption(opt.to_string())) - }; - - names.push(opt); - - let arg_follows = match opts[opt_id].hasarg { - Yes | Maybe => true, - No => false - }; - - let next = j + ch.len_utf8(); - if arg_follows && next < curlen { - i_arg = Some((&cur[next..curlen]).to_string()); - break; - } - - j = next; - } - } - let mut name_pos = 0; - for nm in &names { - name_pos += 1; - let optid = match find_opt(&opts, (*nm).clone()) { - Some(id) => id, - None => return Err(UnrecognizedOption(nm.to_string())) - }; - match opts[optid].hasarg { - No => { - if name_pos == names.len() && !i_arg.is_none() { - return Err(UnexpectedArgument(nm.to_string())); - } - let v = &mut vals[optid]; - v.push(Given); - } - Maybe => { - if !i_arg.is_none() { - let v = &mut vals[optid]; - v.push(Val((i_arg.clone()) - .unwrap())); - } else if name_pos < names.len() || i + 1 == l || - is_arg(&args[i + 1][..]) { - let v = &mut vals[optid]; - v.push(Given); - } else { - i += 1; - let v = &mut vals[optid]; - v.push(Val(args[i].clone())); - } - } - Yes => { - if !i_arg.is_none() { - let v = &mut vals[optid]; - v.push(Val(i_arg.clone().unwrap())); - } else if i + 1 == l { - return Err(ArgumentMissing(nm.to_string())); - } else { - i += 1; - let v = &mut vals[optid]; - v.push(Val(args[i].clone())); - } - } - } - } - } - i += 1; - } - for i in 0..n_opts { - let n = vals[i].len(); - let occ = opts[i].occur; - if occ == Req && n == 0 { - return Err(OptionMissing(opts[i].name.to_string())); - } - if occ != Multi && n > 1 { - return Err(OptionDuplicated(opts[i].name.to_string())); - } - } - Ok(Matches { - opts: opts, - vals: vals, - free: free - }) -} - -/// Derive a usage message from a set of long options. -pub fn usage(brief: &str, opts: &[OptGroup]) -> String { - - let desc_sep = format!("\n{}", repeat(" ").take(24).collect::()); - - let rows = opts.iter().map(|optref| { - let OptGroup{short_name, - long_name, - hint, - desc, - hasarg, - ..} = (*optref).clone(); - - let mut row = repeat(" ").take(4).collect::(); - - // short option - match short_name.len() { - 0 => {} - 1 => { - row.push('-'); - row.push_str(&short_name[..]); - row.push(' '); - } - _ => panic!("the short name should only be 1 ascii char long"), - } - - // long option - match long_name.len() { - 0 => {} - _ => { - row.push_str("--"); - row.push_str(&long_name[..]); - row.push(' '); - } - } - - // arg - match hasarg { - No => {} - Yes => row.push_str(&hint[..]), - Maybe => { - row.push('['); - row.push_str(&hint[..]); - row.push(']'); - } - } - - // FIXME: #5516 should be graphemes not codepoints - // here we just need to indent the start of the description - let rowlen = row.chars().count(); - if rowlen < 24 { - for _ in 0..24 - rowlen { - row.push(' '); - } - } else { - row.push_str(&desc_sep[..]); - } - - // Normalize desc to contain words separated by one space character - let mut desc_normalized_whitespace = String::new(); - for word in desc.split_whitespace() { - desc_normalized_whitespace.push_str(word); - desc_normalized_whitespace.push(' '); - } - - // FIXME: #5516 should be graphemes not codepoints - let mut desc_rows = Vec::new(); - each_split_within(&desc_normalized_whitespace[..], 54, |substr| { - desc_rows.push(substr.to_string()); - true - }); - - // FIXME: #5516 should be graphemes not codepoints - // wrapped description - row.push_str(&desc_rows.connect(&desc_sep[..])); - - row - }); - - format!("{}\n\nOptions:\n{}\n", brief, - rows.collect::>().connect("\n")) -} - fn format_option(opt: &OptGroup) -> String { let mut line = String::new(); @@ -801,12 +845,12 @@ fn format_option(opt: &OptGroup) -> String { } // Use short_name is possible, but fallback to long_name. - if !opt.short_name.is_empty() { + if opt.short_name.len() > 0 { line.push('-'); - line.push_str(&opt.short_name[..]); + line.push_str(&opt.short_name); } else { line.push_str("--"); - line.push_str(&opt.long_name[..]); + line.push_str(&opt.long_name); } if opt.hasarg != No { @@ -814,7 +858,7 @@ fn format_option(opt: &OptGroup) -> String { if opt.hasarg == Maybe { line.push('['); } - line.push_str(&opt.hint[..]); + line.push_str(&opt.hint); if opt.hasarg == Maybe { line.push(']'); } @@ -830,28 +874,20 @@ fn format_option(opt: &OptGroup) -> String { line } -/// Derive a short one-line usage summary from a set of long options. -pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> String { - let mut line = format!("Usage: {} ", program_name); - line.push_str(&opts.iter() - .map(format_option) - .collect::>() - .connect(" ")[..]); - line -} - -#[derive(Copy, Clone)] +#[derive(Clone, Copy)] enum SplitWithinState { A, // leading whitespace, initial state B, // words C, // internal and trailing whitespace } -#[derive(Copy, Clone)] + +#[derive(Clone, Copy)] enum Whitespace { Ws, // current char is whitespace Cr // current char is not whitespace } -#[derive(Copy, Clone)] + +#[derive(Clone, Copy)] enum LengthLimit { UnderLim, // current char makes current substring still fit in limit OverLim // current char makes current substring no longer fit in limit @@ -869,9 +905,8 @@ enum LengthLimit { /// /// Panics during iteration if the string contains a non-whitespace /// sequence longer than the limit. -fn each_split_within(ss: &str, lim: usize, mut it: F) -> bool where - F: FnMut(&str) -> bool -{ +fn each_split_within<'a, F>(ss: &'a str, lim: usize, mut it: F) + -> bool where F: FnMut(&'a str) -> bool { // Just for fun, let's write this as a state machine: let mut slice_start = 0; @@ -888,7 +923,7 @@ fn each_split_within(ss: &str, lim: usize, mut it: F) -> bool where lim = fake_i; } - let mut machine = |cont: &mut bool, (i, c): (usize, char)| -> bool { + let mut machine = |cont: &mut bool, (i, c): (usize, char)| { let whitespace = if c.is_whitespace() { Ws } else { Cr }; let limit = if (i - slice_start + 1) <= lim { UnderLim } else { OverLim }; @@ -969,19 +1004,16 @@ fn test_split_within() { #[cfg(test)] mod tests { - use super::*; + use super::{HasArg, Name, Occur, Opt, Options, ParsingStyle}; use super::Fail::*; - use std::result::Result::{Err, Ok}; - use std::result; - // Tests for reqopt #[test] fn test_reqopt() { let long_args = vec!("--test=20".to_string()); - let opts = vec!(reqopt("t", "test", "testing", "TEST")); - let rs = getopts(&long_args, &opts); - match rs { + let mut opts = Options::new(); + opts.reqopt("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { Ok(ref m) => { assert!(m.opt_present("test")); assert_eq!(m.opt_str("test").unwrap(), "20"); @@ -991,7 +1023,7 @@ mod tests { _ => { panic!("test_reqopt failed (long arg)"); } } let short_args = vec!("-t".to_string(), "20".to_string()); - match getopts(&short_args, &opts) { + match opts.parse(&short_args) { Ok(ref m) => { assert!((m.opt_present("test"))); assert_eq!(m.opt_str("test").unwrap(), "20"); @@ -1005,9 +1037,9 @@ mod tests { #[test] fn test_reqopt_missing() { let args = vec!("blah".to_string()); - let opts = vec!(reqopt("t", "test", "testing", "TEST")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .reqopt("t", "test", "testing", "TEST") + .parse(&args) { Err(OptionMissing(_)) => {}, _ => panic!() } @@ -1016,14 +1048,14 @@ mod tests { #[test] fn test_reqopt_no_arg() { let long_args = vec!("--test".to_string()); - let opts = vec!(reqopt("t", "test", "testing", "TEST")); - let rs = getopts(&long_args, &opts); - match rs { + let mut opts = Options::new(); + opts.reqopt("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { Err(ArgumentMissing(_)) => {}, _ => panic!() } let short_args = vec!("-t".to_string()); - match getopts(&short_args, &opts) { + match opts.parse(&short_args) { Err(ArgumentMissing(_)) => {}, _ => panic!() } @@ -1032,9 +1064,9 @@ mod tests { #[test] fn test_reqopt_multi() { let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string()); - let opts = vec!(reqopt("t", "test", "testing", "TEST")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .reqopt("t", "test", "testing", "TEST") + .parse(&args) { Err(OptionDuplicated(_)) => {}, _ => panic!() } @@ -1044,9 +1076,9 @@ mod tests { #[test] fn test_optopt() { let long_args = vec!("--test=20".to_string()); - let opts = vec!(optopt("t", "test", "testing", "TEST")); - let rs = getopts(&long_args, &opts); - match rs { + let mut opts = Options::new(); + opts.optopt("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { Ok(ref m) => { assert!(m.opt_present("test")); assert_eq!(m.opt_str("test").unwrap(), "20"); @@ -1056,7 +1088,7 @@ mod tests { _ => panic!() } let short_args = vec!("-t".to_string(), "20".to_string()); - match getopts(&short_args, &opts) { + match opts.parse(&short_args) { Ok(ref m) => { assert!((m.opt_present("test"))); assert_eq!(m.opt_str("test").unwrap(), "20"); @@ -1070,9 +1102,9 @@ mod tests { #[test] fn test_optopt_missing() { let args = vec!("blah".to_string()); - let opts = vec!(optopt("t", "test", "testing", "TEST")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optopt("t", "test", "testing", "TEST") + .parse(&args) { Ok(ref m) => { assert!(!m.opt_present("test")); assert!(!m.opt_present("t")); @@ -1084,14 +1116,14 @@ mod tests { #[test] fn test_optopt_no_arg() { let long_args = vec!("--test".to_string()); - let opts = vec!(optopt("t", "test", "testing", "TEST")); - let rs = getopts(&long_args, &opts); - match rs { + let mut opts = Options::new(); + opts.optopt("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { Err(ArgumentMissing(_)) => {}, _ => panic!() } let short_args = vec!("-t".to_string()); - match getopts(&short_args, &opts) { + match opts.parse(&short_args) { Err(ArgumentMissing(_)) => {}, _ => panic!() } @@ -1100,9 +1132,9 @@ mod tests { #[test] fn test_optopt_multi() { let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string()); - let opts = vec!(optopt("t", "test", "testing", "TEST")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optopt("t", "test", "testing", "TEST") + .parse(&args) { Err(OptionDuplicated(_)) => {}, _ => panic!() } @@ -1112,9 +1144,9 @@ mod tests { #[test] fn test_optflag() { let long_args = vec!("--test".to_string()); - let opts = vec!(optflag("t", "test", "testing")); - let rs = getopts(&long_args, &opts); - match rs { + let mut opts = Options::new(); + opts.optflag("t", "test", "testing"); + match opts.parse(&long_args) { Ok(ref m) => { assert!(m.opt_present("test")); assert!(m.opt_present("t")); @@ -1122,7 +1154,7 @@ mod tests { _ => panic!() } let short_args = vec!("-t".to_string()); - match getopts(&short_args, &opts) { + match opts.parse(&short_args) { Ok(ref m) => { assert!(m.opt_present("test")); assert!(m.opt_present("t")); @@ -1134,9 +1166,9 @@ mod tests { #[test] fn test_optflag_missing() { let args = vec!("blah".to_string()); - let opts = vec!(optflag("t", "test", "testing")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optflag("t", "test", "testing") + .parse(&args) { Ok(ref m) => { assert!(!m.opt_present("test")); assert!(!m.opt_present("t")); @@ -1148,9 +1180,9 @@ mod tests { #[test] fn test_optflag_long_arg() { let args = vec!("--test=20".to_string()); - let opts = vec!(optflag("t", "test", "testing")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optflag("t", "test", "testing") + .parse(&args) { Err(UnexpectedArgument(_)) => {}, _ => panic!() } @@ -1159,9 +1191,9 @@ mod tests { #[test] fn test_optflag_multi() { let args = vec!("--test".to_string(), "-t".to_string()); - let opts = vec!(optflag("t", "test", "testing")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optflag("t", "test", "testing") + .parse(&args) { Err(OptionDuplicated(_)) => {}, _ => panic!() } @@ -1170,9 +1202,9 @@ mod tests { #[test] fn test_optflag_short_arg() { let args = vec!("-t".to_string(), "20".to_string()); - let opts = vec!(optflag("t", "test", "testing")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optflag("t", "test", "testing") + .parse(&args) { Ok(ref m) => { // The next variable after the flag is just a free argument @@ -1186,9 +1218,9 @@ mod tests { #[test] fn test_optflagmulti_short1() { let args = vec!("-v".to_string()); - let opts = vec!(optflagmulti("v", "verbose", "verbosity")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { Ok(ref m) => { assert_eq!(m.opt_count("v"), 1); } @@ -1199,9 +1231,9 @@ mod tests { #[test] fn test_optflagmulti_short2a() { let args = vec!("-v".to_string(), "-v".to_string()); - let opts = vec!(optflagmulti("v", "verbose", "verbosity")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { Ok(ref m) => { assert_eq!(m.opt_count("v"), 2); } @@ -1212,9 +1244,9 @@ mod tests { #[test] fn test_optflagmulti_short2b() { let args = vec!("-vv".to_string()); - let opts = vec!(optflagmulti("v", "verbose", "verbosity")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { Ok(ref m) => { assert_eq!(m.opt_count("v"), 2); } @@ -1225,9 +1257,9 @@ mod tests { #[test] fn test_optflagmulti_long1() { let args = vec!("--verbose".to_string()); - let opts = vec!(optflagmulti("v", "verbose", "verbosity")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { Ok(ref m) => { assert_eq!(m.opt_count("verbose"), 1); } @@ -1238,9 +1270,9 @@ mod tests { #[test] fn test_optflagmulti_long2() { let args = vec!("--verbose".to_string(), "--verbose".to_string()); - let opts = vec!(optflagmulti("v", "verbose", "verbosity")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { Ok(ref m) => { assert_eq!(m.opt_count("verbose"), 2); } @@ -1252,9 +1284,9 @@ mod tests { fn test_optflagmulti_mix() { let args = vec!("--verbose".to_string(), "-v".to_string(), "-vv".to_string(), "verbose".to_string()); - let opts = vec!(optflagmulti("v", "verbose", "verbosity")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { Ok(ref m) => { assert_eq!(m.opt_count("verbose"), 4); assert_eq!(m.opt_count("v"), 4); @@ -1263,13 +1295,44 @@ mod tests { } } + // Tests for optflagopt + #[test] + fn test_optflagopt() { + let long_args = vec!("--test".to_string()); + let mut opts = Options::new(); + opts.optflag("t", "test", "testing"); + match opts.parse(&long_args) { + Ok(ref m) => { + assert!(m.opt_present("test")); + assert!(m.opt_present("t")); + } + _ => panic!() + } + let short_args = vec!("-t".to_string()); + match opts.parse(&short_args) { + Ok(ref m) => { + assert!(m.opt_present("test")); + assert!(m.opt_present("t")); + } + _ => panic!() + } + let no_args: Vec = vec!(); + match opts.parse(&no_args) { + Ok(ref m) => { + assert!(!m.opt_present("test")); + assert!(!m.opt_present("t")); + } + _ => panic!() + } + } + // Tests for optmulti #[test] fn test_optmulti() { let long_args = vec!("--test=20".to_string()); - let opts = vec!(optmulti("t", "test", "testing", "TEST")); - let rs = getopts(&long_args, &opts); - match rs { + let mut opts = Options::new(); + opts.optmulti("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { Ok(ref m) => { assert!((m.opt_present("test"))); assert_eq!(m.opt_str("test").unwrap(), "20"); @@ -1279,7 +1342,7 @@ mod tests { _ => panic!() } let short_args = vec!("-t".to_string(), "20".to_string()); - match getopts(&short_args, &opts) { + match opts.parse(&short_args) { Ok(ref m) => { assert!((m.opt_present("test"))); assert_eq!(m.opt_str("test").unwrap(), "20"); @@ -1293,9 +1356,9 @@ mod tests { #[test] fn test_optmulti_missing() { let args = vec!("blah".to_string()); - let opts = vec!(optmulti("t", "test", "testing", "TEST")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optmulti("t", "test", "testing", "TEST") + .parse(&args) { Ok(ref m) => { assert!(!m.opt_present("test")); assert!(!m.opt_present("t")); @@ -1307,14 +1370,14 @@ mod tests { #[test] fn test_optmulti_no_arg() { let long_args = vec!("--test".to_string()); - let opts = vec!(optmulti("t", "test", "testing", "TEST")); - let rs = getopts(&long_args, &opts); - match rs { + let mut opts = Options::new(); + opts.optmulti("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { Err(ArgumentMissing(_)) => {}, _ => panic!() } let short_args = vec!("-t".to_string()); - match getopts(&short_args, &opts) { + match opts.parse(&short_args) { Err(ArgumentMissing(_)) => {}, _ => panic!() } @@ -1323,9 +1386,9 @@ mod tests { #[test] fn test_optmulti_multi() { let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string()); - let opts = vec!(optmulti("t", "test", "testing", "TEST")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optmulti("t", "test", "testing", "TEST") + .parse(&args) { Ok(ref m) => { assert!(m.opt_present("test")); assert_eq!(m.opt_str("test").unwrap(), "20"); @@ -1339,17 +1402,29 @@ mod tests { } } + #[test] + fn test_free_argument_is_hyphen() { + let args = vec!("-".to_string()); + match Options::new().parse(&args) { + Ok(ref m) => { + assert_eq!(m.free.len(), 1); + assert_eq!(m.free[0], "-"); + } + _ => panic!() + } + } + #[test] fn test_unrecognized_option() { let long_args = vec!("--untest".to_string()); - let opts = vec!(optmulti("t", "test", "testing", "TEST")); - let rs = getopts(&long_args, &opts); - match rs { + let mut opts = Options::new(); + opts.optmulti("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { Err(UnrecognizedOption(_)) => {}, _ => panic!() } let short_args = vec!("-u".to_string()); - match getopts(&short_args, &opts) { + match opts.parse(&short_args) { Err(UnrecognizedOption(_)) => {}, _ => panic!() } @@ -1374,16 +1449,15 @@ mod tests { "-A B".to_string(), "-n".to_string(), "-60 70".to_string()); - let opts = - vec!(optopt("s", "something", "something", "SOMETHING"), - optflag("", "flag", "a flag"), - reqopt("", "long", "hi", "LONG"), - optflag("f", "", "another flag"), - optmulti("m", "", "mmmmmm", "YUM"), - optmulti("n", "", "nothing", "NOTHING"), - optopt("", "notpresent", "nothing to see here", "NOPE")); - let rs = getopts(&args, &opts); - match rs { + match Options::new() + .optopt("s", "something", "something", "SOMETHING") + .optflag("", "flag", "a flag") + .reqopt("", "long", "hi", "LONG") + .optflag("f", "", "another flag") + .optmulti("m", "", "mmmmmm", "YUM") + .optmulti("n", "", "nothing", "NOTHING") + .optopt("", "notpresent", "nothing to see here", "NOPE") + .parse(&args) { Ok(ref m) => { assert!(m.free[0] == "prog"); assert!(m.free[1] == "free1"); @@ -1404,16 +1478,42 @@ mod tests { } } + #[test] + fn test_mixed_stop() { + let args = + vec!("-a".to_string(), + "b".to_string(), + "-c".to_string(), + "d".to_string()); + match Options::new() + .parsing_style(ParsingStyle::StopAtFirstFree) + .optflag("a", "", "") + .optopt("c", "", "", "") + .parse(&args) { + Ok(ref m) => { + println!("{}", m.opt_present("c")); + assert!(m.opt_present("a")); + assert!(!m.opt_present("c")); + assert_eq!(m.free.len(), 3); + assert_eq!(m.free[0], "b"); + assert_eq!(m.free[1], "-c"); + assert_eq!(m.free[2], "d"); + } + _ => panic!() + } + } + #[test] fn test_multi() { - let opts = vec!(optopt("e", "", "encrypt", "ENCRYPT"), - optopt("", "encrypt", "encrypt", "ENCRYPT"), - optopt("f", "", "flag", "FLAG")); + let mut opts = Options::new(); + opts.optopt("e", "", "encrypt", "ENCRYPT"); + opts.optopt("", "encrypt", "encrypt", "ENCRYPT"); + opts.optopt("f", "", "flag", "FLAG"); let args_single = vec!("-e".to_string(), "foo".to_string()); - let matches_single = &match getopts(&args_single, &opts) { - result::Result::Ok(m) => m, - result::Result::Err(_) => panic!() + let matches_single = &match opts.parse(&args_single) { + Ok(m) => m, + Err(_) => panic!() }; assert!(matches_single.opts_present(&["e".to_string()])); assert!(matches_single.opts_present(&["encrypt".to_string(), "e".to_string()])); @@ -1430,9 +1530,9 @@ mod tests { let args_both = vec!("-e".to_string(), "foo".to_string(), "--encrypt".to_string(), "foo".to_string()); - let matches_both = &match getopts(&args_both, &opts) { - result::Result::Ok(m) => m, - result::Result::Err(_) => panic!() + let matches_both = &match opts.parse(&args_both) { + Ok(m) => m, + Err(_) => panic!() }; assert!(matches_both.opts_present(&["e".to_string()])); assert!(matches_both.opts_present(&["encrypt".to_string()])); @@ -1453,11 +1553,12 @@ mod tests { #[test] fn test_nospace() { let args = vec!("-Lfoo".to_string(), "-M.".to_string()); - let opts = vec!(optmulti("L", "", "library directory", "LIB"), - optmulti("M", "", "something", "MMMM")); - let matches = &match getopts(&args, &opts) { - result::Result::Ok(m) => m, - result::Result::Err(_) => panic!() + let matches = &match Options::new() + .optmulti("L", "", "library directory", "LIB") + .optmulti("M", "", "something", "MMMM") + .parse(&args) { + Ok(m) => m, + Err(_) => panic!() }; assert!(matches.opts_present(&["L".to_string()])); assert_eq!(matches.opts_str(&["L".to_string()]).unwrap(), "foo"); @@ -1469,11 +1570,12 @@ mod tests { #[test] fn test_nospace_conflict() { let args = vec!("-vvLverbose".to_string(), "-v".to_string() ); - let opts = vec!(optmulti("L", "", "library directory", "LIB"), - optflagmulti("v", "verbose", "Verbose")); - let matches = &match getopts(&args, &opts) { - result::Result::Ok(m) => m, - result::Result::Err(e) => panic!( "{}", e ) + let matches = &match Options::new() + .optmulti("L", "", "library directory", "LIB") + .optflagmulti("v", "verbose", "Verbose") + .parse(&args) { + Ok(m) => m, + Err(e) => panic!( "{}", e ) }; assert!(matches.opts_present(&["L".to_string()])); assert_eq!(matches.opts_str(&["L".to_string()]).unwrap(), "verbose"); @@ -1493,32 +1595,33 @@ mod tests { hasarg: HasArg::Yes, occur: Occur::Req, aliases: Vec::new() }); - let verbose = reqopt("b", "banana", "some bananas", "VAL"); - + let mut opts = Options::new(); + opts.reqopt("b", "banana", "some bananas", "VAL"); + let ref verbose = opts.grps[0]; assert!(verbose.long_to_short() == short); } #[test] fn test_aliases_long_and_short() { - let opts = vec!( - optflagmulti("a", "apple", "Desc")); - let args = vec!("-a".to_string(), "--apple".to_string(), "-a".to_string()); - let matches = getopts(&args, &opts).unwrap(); + let matches = Options::new() + .optflagmulti("a", "apple", "Desc") + .parse(&args) + .unwrap(); assert_eq!(3, matches.opt_count("a")); assert_eq!(3, matches.opt_count("apple")); } #[test] fn test_usage() { - let optgroups = vec!( - reqopt("b", "banana", "Desc", "VAL"), - optopt("a", "012345678901234567890123456789", - "Desc", "VAL"), - optflag("k", "kiwi", "Desc"), - optflagopt("p", "", "Desc", "VAL"), - optmulti("l", "", "Desc", "VAL")); + let mut opts = Options::new(); + opts.reqopt("b", "banana", "Desc", "VAL"); + opts.optopt("a", "012345678901234567890123456789", + "Desc", "VAL"); + opts.optflag("k", "kiwi", "Desc"); + opts.optflagopt("p", "", "Desc", "VAL"); + opts.optmulti("l", "", "Desc", "VAL"); let expected = "Usage: fruits @@ -1532,7 +1635,7 @@ Options: -l VAL Desc "; - let generated_usage = usage("Usage: fruits", &optgroups); + let generated_usage = opts.usage("Usage: fruits"); debug!("expected: <<{}>>", expected); debug!("generated: <<{}>>", generated_usage); @@ -1544,11 +1647,11 @@ Options: // indentation should be 24 spaces // lines wrap after 78: or rather descriptions wrap after 54 - let optgroups = vec!( - optflag("k", "kiwi", - "This is a long description which won't be wrapped..+.."), // 54 - optflag("a", "apple", - "This is a long description which _will_ be wrapped..+..")); + let mut opts = Options::new(); + opts.optflag("k", "kiwi", + "This is a long description which won't be wrapped..+.."); // 54 + opts.optflag("a", "apple", + "This is a long description which _will_ be wrapped..+.."); let expected = "Usage: fruits @@ -1559,7 +1662,7 @@ Options: wrapped..+.. "; - let usage = usage("Usage: fruits", &optgroups); + let usage = opts.usage("Usage: fruits"); debug!("expected: <<{}>>", expected); debug!("generated: <<{}>>", usage); @@ -1568,12 +1671,12 @@ Options: #[test] fn test_usage_description_multibyte_handling() { - let optgroups = vec!( - optflag("k", "k\u{2013}w\u{2013}", - "The word kiwi is normally spelled with two i's"), - optflag("a", "apple", - "This \u{201C}description\u{201D} has some characters that could \ -confuse the line wrapping; an apple costs 0.51€ in some parts of Europe.")); + let mut opts = Options::new(); + opts.optflag("k", "k\u{2013}w\u{2013}", + "The word kiwi is normally spelled with two i's"); + opts.optflag("a", "apple", + "This \u{201C}description\u{201D} has some characters that could \ +confuse the line wrapping; an apple costs 0.51€ in some parts of Europe."); let expected = "Usage: fruits @@ -1585,7 +1688,7 @@ Options: some parts of Europe. "; - let usage = usage("Usage: fruits", &optgroups); + let usage = opts.usage("Usage: fruits"); debug!("expected: <<{}>>", expected); debug!("generated: <<{}>>", usage); @@ -1594,16 +1697,16 @@ Options: #[test] fn test_short_usage() { - let optgroups = vec!( - reqopt("b", "banana", "Desc", "VAL"), - optopt("a", "012345678901234567890123456789", - "Desc", "VAL"), - optflag("k", "kiwi", "Desc"), - optflagopt("p", "", "Desc", "VAL"), - optmulti("l", "", "Desc", "VAL")); + let mut opts = Options::new(); + opts.reqopt("b", "banana", "Desc", "VAL"); + opts.optopt("a", "012345678901234567890123456789", + "Desc", "VAL"); + opts.optflag("k", "kiwi", "Desc"); + opts.optflagopt("p", "", "Desc", "VAL"); + opts.optmulti("l", "", "Desc", "VAL"); let expected = "Usage: fruits -b VAL [-a VAL] [-k] [-p [VAL]] [-l VAL]..".to_string(); - let generated_usage = short_usage("fruits", &optgroups); + let generated_usage = opts.short_usage("fruits"); debug!("expected: <<{}>>", expected); debug!("generated: <<{}>>", generated_usage); diff --git a/src/external/getopts/tests/smoke.rs b/src/external/getopts/tests/smoke.rs new file mode 100644 index 0000000000000..a46f9c0167ab3 --- /dev/null +++ b/src/external/getopts/tests/smoke.rs @@ -0,0 +1,8 @@ +extern crate getopts; + +use std::env; + +#[test] +fn main() { + getopts::Options::new().parse(env::args()).unwrap(); +} diff --git a/src/external/rustc_serialize/.gitignore b/src/external/rustc_serialize/.gitignore new file mode 100644 index 0000000000000..4fffb2f89cbd8 --- /dev/null +++ b/src/external/rustc_serialize/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/src/external/rustc_serialize/.travis.yml b/src/external/rustc_serialize/.travis.yml new file mode 100644 index 0000000000000..eb446b23fe6bb --- /dev/null +++ b/src/external/rustc_serialize/.travis.yml @@ -0,0 +1,26 @@ +language: rust +rust: + - 1.0.0 + - beta + - nightly +sudo: false +script: + - cargo build --verbose + - cargo test --verbose + - | + [ $TRAVIS_RUST_VERSION != nightly ] || cargo bench --verbose + - cargo doc +after_success: | + [ $TRAVIS_BRANCH = master ] && + [ $TRAVIS_PULL_REQUEST = false ] && + [ $TRAVIS_RUST_VERSION = nightly ] && + echo '' > target/doc/index.html && + pip install ghp-import --user $USER && + $HOME/.local/bin/ghp-import -n target/doc && + git push -qf https://${TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages +env: + global: + secure: f0CwX+CnvRbEqK3H6zhBQe4u0t14OQvyd6nUhq/oXkJ6LdtrSx+qQtLSmAU7L8p1IXyP8csxv37bTdEB7/U1c6bJcN2OXHrw9nD0NDvZEs1zSZvFQBm+YBwV7EaposPHCeqee3X9b00g7+bObywMYtEkk7yD2NiOY9SjMRcjTLQ= +notifications: + email: + on_success: never diff --git a/src/external/rustc_serialize/Cargo.toml b/src/external/rustc_serialize/Cargo.toml new file mode 100644 index 0000000000000..1f8f70c5761ea --- /dev/null +++ b/src/external/rustc_serialize/Cargo.toml @@ -0,0 +1,18 @@ +[package] + +name = "rustc-serialize" +version = "0.3.14" +authors = ["The Rust Project Developers"] +license = "MIT/Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-lang/rustc-serialize" +homepage = "https://github.com/rust-lang/rustc-serialize" +documentation = "http://doc.rust-lang.org/rustc-serialize" +description = """ +Generic serialization/deserialization support corresponding to the +`derive(RustcEncodable, RustcDecodable)` mode in the compiler. Also includes +support for hex, base64, and json encoding and decoding. +""" + +[dev-dependencies] +rand = "0.3" diff --git a/src/external/rustc_serialize/LICENSE-APACHE b/src/external/rustc_serialize/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/src/external/rustc_serialize/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/external/rustc_serialize/LICENSE-MIT b/src/external/rustc_serialize/LICENSE-MIT new file mode 100644 index 0000000000000..39d4bdb5acd31 --- /dev/null +++ b/src/external/rustc_serialize/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/external/rustc_serialize/README.md b/src/external/rustc_serialize/README.md new file mode 100644 index 0000000000000..e8db8b91e1d7b --- /dev/null +++ b/src/external/rustc_serialize/README.md @@ -0,0 +1,24 @@ +# rustc-serialize + +Serialization and deserialization support provided by the compiler in the form +of `derive(RustcEncodable, RustcDecodable)`. + +[![Linux Build Status](https://travis-ci.org/rust-lang/rustc-serialize.svg?branch=master)](https://travis-ci.org/rust-lang/rustc-serialize) +[![Windows Build Status](https://ci.appveyor.com/api/projects/status/ka194de75aapwpft?svg=true)](https://ci.appveyor.com/project/alexcrichton/rustc-serialize) + +[Documentation](http://doc.rust-lang.org/rustc-serialize) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +rustc-serialize = "0.3" +``` + +and this to your crate root: + +```rust +extern crate rustc_serialize; +``` diff --git a/src/external/rustc_serialize/appveyor.yml b/src/external/rustc_serialize/appveyor.yml new file mode 100644 index 0000000000000..f74c851ad7100 --- /dev/null +++ b/src/external/rustc_serialize/appveyor.yml @@ -0,0 +1,11 @@ +install: + - ps: Start-FileDownload 'https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe' + - rust-nightly-i686-pc-windows-gnu.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --verbose diff --git a/src/external/rustc_serialize/benches/base64.rs b/src/external/rustc_serialize/benches/base64.rs new file mode 100644 index 0000000000000..629cb0a909b53 --- /dev/null +++ b/src/external/rustc_serialize/benches/base64.rs @@ -0,0 +1,29 @@ +#![feature(test)] + +extern crate test; +extern crate rustc_serialize; + +use rustc_serialize::base64::{FromBase64, ToBase64, STANDARD}; +use test::Bencher; + +#[bench] +fn bench_to_base64(b: &mut Bencher) { + let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; + b.iter(|| { + s.as_bytes().to_base64(STANDARD); + }); + b.bytes = s.len() as u64; +} + +#[bench] +fn bench_from_base64(b: &mut Bencher) { + let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; + let sb = s.as_bytes().to_base64(STANDARD); + b.iter(|| { + sb.from_base64().unwrap(); + }); + b.bytes = sb.len() as u64; +} + diff --git a/src/external/rustc_serialize/benches/hex.rs b/src/external/rustc_serialize/benches/hex.rs new file mode 100644 index 0000000000000..97a7735e81754 --- /dev/null +++ b/src/external/rustc_serialize/benches/hex.rs @@ -0,0 +1,28 @@ +#![feature(test)] + +extern crate test; +extern crate rustc_serialize; + +use test::Bencher; +use rustc_serialize::hex::{FromHex, ToHex}; + +#[bench] +fn bench_to_hex(b: &mut Bencher) { + let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; + b.iter(|| { + s.as_bytes().to_hex(); + }); + b.bytes = s.len() as u64; +} + +#[bench] +fn bench_from_hex(b: &mut Bencher) { + let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; + let sb = s.as_bytes().to_hex(); + b.iter(|| { + sb.from_hex().unwrap(); + }); + b.bytes = sb.len() as u64; +} diff --git a/src/external/rustc_serialize/benches/json.rs b/src/external/rustc_serialize/benches/json.rs new file mode 100644 index 0000000000000..20768e116a7c4 --- /dev/null +++ b/src/external/rustc_serialize/benches/json.rs @@ -0,0 +1,84 @@ +#![feature(test)] + +extern crate test; +extern crate rustc_serialize; + +use std::string; +use rustc_serialize::json::{Json, Parser}; +use test::Bencher; + +#[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 _ = Json::from_str(r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#); + }); +} + +#[bench] +fn bench_decode_hex_escape(b: &mut Bencher) { + let mut src = "\"".to_string(); + for _ in 0..10 { + src.push_str("\\uF975\\uf9bc\\uF9A0\\uF9C4\\uF975\\uf9bc\\uF9A0\\uF9C4"); + } + src.push_str("\""); + b.iter( || { + let _ = Json::from_str(&src); + }); +} + +fn big_json() -> string::String { + let mut src = "[\n".to_string(); + for _ in 0..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 _ = Json::from_str(&src); }); +} diff --git a/src/external/rustc_serialize/src/base64.rs b/src/external/rustc_serialize/src/base64.rs new file mode 100644 index 0000000000000..5449d7bade19c --- /dev/null +++ b/src/external/rustc_serialize/src/base64.rs @@ -0,0 +1,406 @@ +// 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. +// +// ignore-lexer-test FIXME #15679 + +//! Base64 binary-to-text encoding + +pub use self::FromBase64Error::*; +pub use self::CharacterSet::*; + +use std::fmt; +use std::error; + +/// Available encoding character sets +#[derive(Clone, Copy)] +pub enum CharacterSet { + /// The standard character set (uses `+` and `/`) + Standard, + /// The URL safe character set (uses `-` and `_`) + UrlSafe +} + +/// Available newline types +#[derive(Clone, Copy)] +pub enum Newline { + /// A linefeed (i.e. Unix-style newline) + LF, + /// A carriage return and a linefeed (i.e. Windows-style newline) + CRLF +} + +/// Contains configuration parameters for `to_base64`. +#[derive(Clone, Copy)] +pub struct Config { + /// Character set to use + pub char_set: CharacterSet, + /// Newline to use + pub newline: Newline, + /// True to pad output with `=` characters + pub pad: bool, + /// `Some(len)` to wrap lines at `len`, `None` to disable line wrapping + pub line_length: Option +} + +/// Configuration for RFC 4648 standard base64 encoding +pub static STANDARD: Config = + Config {char_set: Standard, newline: Newline::CRLF, pad: true, line_length: None}; + +/// Configuration for RFC 4648 base64url encoding +pub static URL_SAFE: Config = + Config {char_set: UrlSafe, newline: Newline::CRLF, pad: false, line_length: None}; + +/// Configuration for RFC 2045 MIME base64 encoding +pub static MIME: Config = + Config {char_set: Standard, newline: Newline::CRLF, pad: true, line_length: Some(76)}; + +static STANDARD_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789+/"; + +static URLSAFE_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789-_"; + +/// A trait for converting a value to base64 encoding. +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; +} + +impl ToBase64 for [u8] { + /// Turn a vector of `u8` bytes into a base64 string. + /// + /// # Example + /// + /// ```rust + /// extern crate rustc_serialize; + /// use rustc_serialize::base64::{ToBase64, STANDARD}; + /// + /// fn main () { + /// let str = [52,32].to_base64(STANDARD); + /// println!("base 64 output: {:?}", str); + /// } + /// ``` + fn to_base64(&self, config: Config) -> String { + let bytes = match config.char_set { + Standard => STANDARD_CHARS, + UrlSafe => URLSAFE_CHARS + }; + + // In general, this Vec only needs (4/3) * self.len() memory, but + // addition is faster than multiplication and division. + let mut v = Vec::with_capacity(self.len() + self.len()); + let mut i = 0; + let mut cur_length = 0; + let len = self.len(); + let mod_len = len % 3; + let cond_len = len - mod_len; + let newline = match config.newline { + Newline::LF => "\n", + Newline::CRLF => "\r\n", + }; + while i < cond_len { + let (first, second, third) = (self[i], self[i + 1], self[i + 2]); + if let Some(line_length) = config.line_length { + if cur_length >= line_length { + v.extend(newline.bytes()); + cur_length = 0; + } + } + + let n = (first as u32) << 16 | + (second as u32) << 8 | + (third as u32); + + // This 24-bit number gets separated into four 6-bit numbers. + v.push(bytes[((n >> 18) & 63) as usize]); + v.push(bytes[((n >> 12) & 63) as usize]); + v.push(bytes[((n >> 6 ) & 63) as usize]); + v.push(bytes[(n & 63) as usize]); + + cur_length += 4; + i += 3; + } + + if mod_len != 0 { + if let Some(line_length) = config.line_length { + if cur_length >= line_length { + v.extend(newline.bytes()); + } + } + } + + // Heh, would be cool if we knew this was exhaustive + // (the dream of bounded integer types) + match mod_len { + 0 => (), + 1 => { + let n = (self[i] as u32) << 16; + v.push(bytes[((n >> 18) & 63) as usize]); + v.push(bytes[((n >> 12) & 63) as usize]); + if config.pad { + v.push(b'='); + v.push(b'='); + } + } + 2 => { + let n = (self[i] as u32) << 16 | + (self[i + 1] as u32) << 8; + v.push(bytes[((n >> 18) & 63) as usize]); + v.push(bytes[((n >> 12) & 63) as usize]); + v.push(bytes[((n >> 6 ) & 63) as usize]); + if config.pad { + v.push(b'='); + } + } + _ => panic!("Algebra is broken, please alert the math police") + } + + unsafe { String::from_utf8_unchecked(v) } + } +} + +/// A trait for converting from base64 encoded values. +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>; +} + +/// Errors that can occur when decoding a base64 encoded string +#[derive(Clone, Copy)] +pub enum FromBase64Error { + /// The input contained a character not part of the base64 format + InvalidBase64Byte(u8, usize), + /// The input had an invalid length + InvalidBase64Length, +} + +impl fmt::Debug for FromBase64Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + InvalidBase64Byte(ch, idx) => + write!(f, "Invalid character '{}' at position {}", ch, idx), + InvalidBase64Length => write!(f, "Invalid length"), + } + } +} + +impl error::Error for FromBase64Error { + fn description(&self) -> &str { + match *self { + InvalidBase64Byte(_, _) => "invalid character", + InvalidBase64Length => "invalid length", + } + } +} + +impl fmt::Display for FromBase64Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self, f) + } +} + +impl FromBase64 for str { + /// Convert any base64 encoded string (literal, `@`, `&`, or `~`) + /// to the byte values it encodes. + /// + /// You can use the `String::from_utf8` function to turn a `Vec` into a + /// string with characters corresponding to those values. + /// + /// # Example + /// + /// This converts a string literal to base64 and back. + /// + /// ```rust + /// extern crate rustc_serialize; + /// use rustc_serialize::base64::{ToBase64, FromBase64, STANDARD}; + /// + /// fn main () { + /// let hello_str = b"Hello, World".to_base64(STANDARD); + /// println!("base64 output: {}", hello_str); + /// let res = hello_str.from_base64(); + /// if res.is_ok() { + /// let opt_bytes = String::from_utf8(res.unwrap()); + /// if opt_bytes.is_ok() { + /// println!("decoded from base64: {:?}", opt_bytes.unwrap()); + /// } + /// } + /// } + /// ``` + #[inline] + fn from_base64(&self) -> Result, FromBase64Error> { + self.as_bytes().from_base64() + } +} + +impl FromBase64 for [u8] { + fn from_base64(&self) -> Result, FromBase64Error> { + let mut r = Vec::with_capacity(self.len()); + let mut buf: u32 = 0; + let mut modulus = 0; + + let mut it = self.iter().enumerate(); + for (idx, &byte) in it.by_ref() { + let val = byte as u32; + + match byte { + b'A'...b'Z' => buf |= val - 0x41, + b'a'...b'z' => buf |= val - 0x47, + b'0'...b'9' => buf |= val + 0x04, + b'+' | b'-' => buf |= 0x3E, + b'/' | b'_' => buf |= 0x3F, + b'\r' | b'\n' => continue, + b'=' => break, + _ => return Err(InvalidBase64Byte(self[idx], idx)), + } + + buf <<= 6; + modulus += 1; + if modulus == 4 { + modulus = 0; + r.push((buf >> 22) as u8); + r.push((buf >> 14) as u8); + r.push((buf >> 6 ) as u8); + } + } + + for (idx, &byte) in it { + match byte { + b'=' | b'\r' | b'\n' => continue, + _ => return Err(InvalidBase64Byte(self[idx], idx)), + } + } + + match modulus { + 2 => { + r.push((buf >> 10) as u8); + } + 3 => { + r.push((buf >> 16) as u8); + r.push((buf >> 8 ) as u8); + } + 0 => (), + _ => return Err(InvalidBase64Length), + } + + Ok(r) + } +} + +#[cfg(test)] +mod tests { + use base64::{Config, Newline, FromBase64, ToBase64, STANDARD, URL_SAFE}; + + #[test] + fn test_to_base64_basic() { + assert_eq!("".as_bytes().to_base64(STANDARD), ""); + assert_eq!("f".as_bytes().to_base64(STANDARD), "Zg=="); + assert_eq!("fo".as_bytes().to_base64(STANDARD), "Zm8="); + assert_eq!("foo".as_bytes().to_base64(STANDARD), "Zm9v"); + assert_eq!("foob".as_bytes().to_base64(STANDARD), "Zm9vYg=="); + assert_eq!("fooba".as_bytes().to_base64(STANDARD), "Zm9vYmE="); + assert_eq!("foobar".as_bytes().to_base64(STANDARD), "Zm9vYmFy"); + } + + #[test] + fn test_to_base64_crlf_line_break() { + assert!(![08; 1000].to_base64(Config {line_length: None, ..STANDARD}) + .contains("\r\n")); + assert_eq!(b"foobar".to_base64(Config {line_length: Some(4), + ..STANDARD}), + "Zm9v\r\nYmFy"); + } + + #[test] + fn test_to_base64_lf_line_break() { + assert!(![08; 1000].to_base64(Config {line_length: None, + newline: Newline::LF, + ..STANDARD}) + .contains("\n")); + assert_eq!(b"foobar".to_base64(Config {line_length: Some(4), + newline: Newline::LF, + ..STANDARD}), + "Zm9v\nYmFy"); + } + + #[test] + fn test_to_base64_padding() { + assert_eq!("f".as_bytes().to_base64(Config {pad: false, ..STANDARD}), "Zg"); + assert_eq!("fo".as_bytes().to_base64(Config {pad: false, ..STANDARD}), "Zm8"); + } + + #[test] + fn test_to_base64_url_safe() { + assert_eq!([251, 255].to_base64(URL_SAFE), "-_8"); + assert_eq!([251, 255].to_base64(STANDARD), "+/8="); + } + + #[test] + fn test_from_base64_basic() { + assert_eq!("".from_base64().unwrap(), b""); + assert_eq!("Zg==".from_base64().unwrap(), b"f"); + assert_eq!("Zm8=".from_base64().unwrap(), b"fo"); + assert_eq!("Zm9v".from_base64().unwrap(), b"foo"); + assert_eq!("Zm9vYg==".from_base64().unwrap(), b"foob"); + assert_eq!("Zm9vYmE=".from_base64().unwrap(), b"fooba"); + assert_eq!("Zm9vYmFy".from_base64().unwrap(), b"foobar"); + } + + #[test] + fn test_from_base64_bytes() { + assert_eq!(b"Zm9vYmFy".from_base64().unwrap(), b"foobar"); + } + + #[test] + fn test_from_base64_newlines() { + assert_eq!("Zm9v\r\nYmFy".from_base64().unwrap(), + b"foobar"); + assert_eq!("Zm9vYg==\r\n".from_base64().unwrap(), + b"foob"); + assert_eq!("Zm9v\nYmFy".from_base64().unwrap(), + b"foobar"); + assert_eq!("Zm9vYg==\n".from_base64().unwrap(), + b"foob"); + } + + #[test] + fn test_from_base64_urlsafe() { + assert_eq!("-_8".from_base64().unwrap(), "+/8=".from_base64().unwrap()); + } + + #[test] + fn test_from_base64_invalid_char() { + assert!("Zm$=".from_base64().is_err()); + assert!("Zg==$".from_base64().is_err()); + } + + #[test] + fn test_from_base64_invalid_padding() { + assert!("Z===".from_base64().is_err()); + } + + #[test] + fn test_base64_random() { + use rand::{thread_rng, Rng}; + + for _ in 0..1000 { + let times = thread_rng().gen_range(1, 100); + let v = thread_rng().gen_iter::().take(times) + .collect::>(); + assert_eq!(v.to_base64(STANDARD) + .from_base64() + .unwrap(), + v); + } + } +} diff --git a/src/libserialize/collection_impls.rs b/src/external/rustc_serialize/src/collection_impls.rs similarity index 66% rename from src/libserialize/collection_impls.rs rename to src/external/rustc_serialize/src/collection_impls.rs index e7430f698e9c9..6ab4b7cef8a53 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/external/rustc_serialize/src/collection_impls.rs @@ -10,14 +10,10 @@ //! Implementations of serialization for structures found in libcollections -use std::usize; -use std::default::Default; use std::hash::Hash; -use std::collections::hash_state::HashState; use {Decodable, Encodable, Decoder, Encoder}; -use std::collections::{LinkedList, VecDeque, BTreeMap, BTreeSet, HashMap, HashSet, VecMap}; -use collections::enum_set::{EnumSet, CLike}; +use std::collections::{LinkedList, VecDeque, BTreeMap, BTreeSet, HashMap, HashSet}; impl< T: Encodable @@ -74,7 +70,7 @@ impl< fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { let mut i = 0; - for (key, val) in self { + 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; @@ -107,7 +103,7 @@ impl< fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { let mut i = 0; - for e in self { + for e in self.iter() { try!(s.emit_seq_elt(i, |s| e.encode(s))); i += 1; } @@ -130,42 +126,14 @@ impl< } } -impl< - T: Encodable + CLike -> Encodable for EnumSet { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - let mut bits = 0; - for item in self { - bits |= item.to_usize(); - } - s.emit_uint(bits) - } -} - -impl< - 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 0..usize::BITS { - if bits & (1 << bit) != 0 { - set.insert(CLike::from_usize(1 << bit)); - } - } - Ok(set) - } -} - -impl Encodable for HashMap +impl Encodable for HashMap where K: Encodable + Hash + Eq, V: Encodable, - S: HashState, { fn encode(&self, e: &mut E) -> Result<(), E::Error> { e.emit_map(self.len(), |e| { let mut i = 0; - for (key, val) in self { + 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; @@ -175,15 +143,13 @@ impl Encodable for HashMap } } -impl Decodable for HashMap +impl Decodable for HashMap where K: Decodable + Hash + Eq, V: Decodable, - S: HashState + Default, { - fn decode(d: &mut D) -> Result, D::Error> { + fn decode(d: &mut D) -> Result, D::Error> { d.read_map(|d, len| { - let state = Default::default(); - let mut map = HashMap::with_capacity_and_hash_state(len, state); + let mut map = HashMap::with_capacity(len); for i in 0..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))); @@ -194,14 +160,11 @@ impl Decodable for HashMap } } -impl Encodable for HashSet - where T: Encodable + Hash + Eq, - S: HashState, -{ +impl Encodable for HashSet where T: Encodable + Hash + Eq { fn encode(&self, s: &mut E) -> Result<(), E::Error> { s.emit_seq(self.len(), |s| { let mut i = 0; - for e in self { + for e in self.iter() { try!(s.emit_seq_elt(i, |s| e.encode(s))); i += 1; } @@ -210,14 +173,10 @@ impl Encodable for HashSet } } -impl Decodable for HashSet - where T: Decodable + Hash + Eq, - S: HashState + Default, -{ - fn decode(d: &mut D) -> Result, D::Error> { +impl Decodable for HashSet where T: Decodable + Hash + Eq, { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { - let state = Default::default(); - let mut set = HashSet::with_capacity_and_hash_state(len, state); + let mut set = HashSet::with_capacity(len); for i in 0..len { set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); } @@ -225,29 +184,3 @@ impl Decodable for HashSet }) } } - -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))); - try!(e.emit_map_elt_val(i, |e| val.encode(e))); - } - Ok(()) - }) - } -} - -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 0..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/hex.rs b/src/external/rustc_serialize/src/hex.rs similarity index 75% rename from src/libserialize/hex.rs rename to src/external/rustc_serialize/src/hex.rs index 87f1dca2caed0..08d25fdf2e36f 100644 --- a/src/libserialize/hex.rs +++ b/src/external/rustc_serialize/src/hex.rs @@ -7,6 +7,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// +// ignore-lexer-test FIXME #15679 //! Hex binary-to-text encoding @@ -22,17 +24,16 @@ pub trait ToHex { fn to_hex(&self) -> String; } -const CHARS: &'static [u8] = b"0123456789abcdef"; +static CHARS: &'static[u8] = b"0123456789abcdef"; impl ToHex for [u8] { /// Turn a vector of `u8` bytes into a hexadecimal string. /// - /// # Examples + /// # Example /// - /// ``` - /// # #![feature(rustc_private)] - /// extern crate serialize; - /// use serialize::hex::ToHex; + /// ```rust + /// extern crate rustc_serialize; + /// use rustc_serialize::hex::ToHex; /// /// fn main () { /// let str = [52,32].to_hex(); @@ -41,7 +42,7 @@ impl ToHex for [u8] { /// ``` fn to_hex(&self) -> String { let mut v = Vec::with_capacity(self.len() * 2); - for &byte in self { + for &byte in self.iter() { v.push(CHARS[(byte >> 4) as usize]); v.push(CHARS[(byte & 0xf) as usize]); } @@ -60,7 +61,7 @@ pub trait FromHex { } /// Errors that can occur when decoding a hex encoded string -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Copy)] pub enum FromHexError { /// The input contained a character not part of the hex format InvalidHexCharacter(char, usize), @@ -68,7 +69,7 @@ pub enum FromHexError { InvalidHexLength, } -impl fmt::Display for FromHexError { +impl fmt::Debug for FromHexError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { InvalidHexCharacter(ch, idx) => @@ -87,6 +88,11 @@ impl error::Error for FromHexError { } } +impl fmt::Display for FromHexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self, f) + } +} impl FromHex for str { /// Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`) @@ -95,14 +101,13 @@ impl FromHex for str { /// You can use the `String::from_utf8` function to turn a /// `Vec` into a string with characters corresponding to those values. /// - /// # Examples + /// # Example /// /// This converts a string literal to hexadecimal and back. /// - /// ``` - /// # #![feature(rustc_private)] - /// extern crate serialize; - /// use serialize::hex::{FromHex, ToHex}; + /// ```rust + /// extern crate rustc_serialize; + /// use rustc_serialize::hex::{FromHex, ToHex}; /// /// fn main () { /// let hello_str = "Hello, World".as_bytes().to_hex(); @@ -117,7 +122,7 @@ impl FromHex for str { // This may be an overestimate if there is any whitespace let mut b = Vec::with_capacity(self.len() / 2); let mut modulus = 0; - let mut buf = 0; + let mut buf = 08; for (idx, byte) in self.bytes().enumerate() { buf <<= 4; @@ -130,7 +135,10 @@ impl FromHex for str { buf >>= 4; continue } - _ => return Err(InvalidHexCharacter(self.char_at(idx), idx)), + _ => { + let ch = self[idx..].chars().next().unwrap(); + return Err(InvalidHexCharacter(ch, idx)) + } } modulus += 1; @@ -149,8 +157,6 @@ impl FromHex for str { #[cfg(test)] mod tests { - extern crate test; - use self::test::Bencher; use hex::{FromHex, ToHex}; #[test] @@ -186,7 +192,7 @@ mod tests { #[test] pub fn test_to_hex_all_bytes() { for i in 0..256 { - assert_eq!([i as u8].to_hex(), format!("{:02x}", i as usize)); + assert_eq!([i as u8].to_hex(), format!("{:02x}", i)); } } @@ -194,33 +200,10 @@ mod tests { pub fn test_from_hex_all_bytes() { for i in 0..256 { let ii: &[u8] = &[i as u8]; - assert_eq!(format!("{:02x}", i as usize).from_hex() - .unwrap(), + assert_eq!(format!("{:02x}", i).from_hex().unwrap(), ii); - assert_eq!(format!("{:02X}", i as usize).from_hex() - .unwrap(), + assert_eq!(format!("{:02X}", i).from_hex().unwrap(), ii); } } - - #[bench] - pub fn bench_to_hex(b: &mut Bencher) { - let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ - ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; - b.iter(|| { - s.as_bytes().to_hex(); - }); - b.bytes = s.len() as u64; - } - - #[bench] - pub fn bench_from_hex(b: &mut Bencher) { - let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ - ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; - let sb = s.as_bytes().to_hex(); - b.iter(|| { - sb.from_hex().unwrap(); - }); - b.bytes = sb.len() as u64; - } } diff --git a/src/libserialize/json.rs b/src/external/rustc_serialize/src/json.rs similarity index 69% rename from src/libserialize/json.rs rename to src/external/rustc_serialize/src/json.rs index 24cc7fe878af4..1fd4c430cda21 100644 --- a/src/libserialize/json.rs +++ b/src/external/rustc_serialize/src/json.rs @@ -11,30 +11,33 @@ // 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. +//! 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): +//! Data types that can be encoded are JavaScript types (see the `Json` enum +//! for more details): //! +//! * `I64`: equivalent to rust's `i64` +//! * `U64`: equivalent to rust's `u64` +//! * `F64`: equivalent to rust's `f64` //! * `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 +//! * `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, their age, address and phone numbers could look like +//! 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, +//! their age, address and phone numbers could look like //! //! ```ignore //! { @@ -55,33 +58,36 @@ //! //! # 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: +//! 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 `rustc_serialize::Encodable` trait. To be +//! able to decode a piece of data, it must implement the +//! `rustc_serialize::Decodable` 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. +//! 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. +//! When using `ToJson` the `Encodable` 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. +//! 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; +//! ```rust +//! extern crate rustc_serialize; +//! use rustc_serialize::json; //! -//! // Automatically generate `Decodable` and `Encodable` trait implementations +//! // Automatically generate `RustcDecodable` and `RustcEncodable` trait +//! // implementations //! #[derive(RustcDecodable, RustcEncodable)] //! pub struct TestStruct { //! data_int: u8, @@ -100,21 +106,20 @@ //! let encoded = json::encode(&object).unwrap(); //! //! // Deserialize using `json::decode` -//! let decoded: TestStruct = json::decode(&encoded[..]).unwrap(); +//! let decoded: TestStruct = json::decode(&encoded).unwrap(); //! } //! ``` //! //! ## Using the `ToJson` trait //! -//! The examples above use the `ToJson` trait to generate the JSON string, which is required -//! for custom mappings. +//! 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::{self, ToJson, Json}; +//! ```rust +//! extern crate rustc_serialize; +//! use rustc_serialize::json::{self, ToJson, Json}; //! //! // A custom data structure //! struct ComplexNum { @@ -130,7 +135,7 @@ //! } //! //! // Only generate `RustcEncodable` trait implementation -//! #[derive(Encodable)] +//! #[derive(RustcEncodable)] //! pub struct ComplexNumRecord { //! uid: u8, //! dsc: String, @@ -151,14 +156,13 @@ //! //! ### Verbose example of `ToJson` usage //! -//! ```notrust -//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment -//! extern crate serialize; +//! ```rust +//! extern crate rustc_serialize; //! use std::collections::BTreeMap; -//! use serialize::json::{self, Json, ToJson}; +//! use rustc_serialize::json::{self, Json, ToJson}; //! //! // Only generate `Decodable` trait implementation -//! #[derive(Decodable)] +//! #[derive(RustcDecodable)] //! pub struct TestStruct { //! data_int: u8, //! data_str: String, @@ -188,7 +192,40 @@ //! let json_str: String = json_obj.to_string(); //! //! // Deserialize like before -//! let decoded: TestStruct = json::decode(json_str)).unwrap(); +//! let decoded: TestStruct = json::decode(&json_str).unwrap(); +//! } +//! ``` +//! +//! ## Parsing a `str` to `Json` and reading the result +//! +//! ```rust +//! extern crate rustc_serialize; +//! use rustc_serialize::json::Json; +//! +//! fn main() { +//! let data = Json::from_str("{\"foo\": 13, \"bar\": \"baz\"}").unwrap(); +//! println!("data: {}", data); +//! // data: {"bar":"baz","foo":13} +//! println!("object? {}", data.is_object()); +//! // object? true +//! +//! let obj = data.as_object().unwrap(); +//! let foo = obj.get("foo").unwrap(); +//! +//! println!("array? {:?}", foo.as_array()); +//! // array? None +//! println!("u64? {:?}", foo.as_u64()); +//! // u64? Some(13u64) +//! +//! for (key, value) in obj.iter() { +//! println!("{}: {}", key, match *value { +//! Json::U64(v) => format!("{} (u64)", v), +//! Json::String(ref v) => format!("{} (string)", v), +//! _ => format!("other") +//! }); +//! } +//! // bar: baz (string) +//! // foo: 13 (u64) //! } //! ``` @@ -200,17 +237,14 @@ use self::ParserState::*; use self::InternalStackElement::*; use std::collections::{HashMap, BTreeMap}; +use std::error::Error as StdError; +use std::i64; use std::io::prelude::*; -use std::io; use std::mem::swap; -use std::num::FpCategory as Fp; use std::ops::Index; use std::str::FromStr; use std::string; -use std::{char, f64, fmt, str}; -use std; -use rustc_unicode::str as unicode_str; -use rustc_unicode::str::Utf16Item; +use std::{char, f64, fmt, io, str}; use Encodable; @@ -233,10 +267,10 @@ 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 } +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, Debug)] +#[derive(Clone, Copy, PartialEq)] pub enum ErrorCode { InvalidSyntax, InvalidNumber, @@ -254,34 +288,51 @@ pub enum ErrorCode { UnexpectedEndOfHexEscape, UnrecognizedHex, NotFourDigit, + ControlCharacterInString, NotUtf8, } -#[derive(Clone, PartialEq, Debug)] +#[derive(Debug)] pub enum ParserError { /// msg, line, col SyntaxError(ErrorCode, usize, usize), - IoError(io::ErrorKind, String), + IoError(io::Error), +} + +impl PartialEq for ParserError { + fn eq(&self, other: &ParserError) -> bool { + match (self, other) { + (&SyntaxError(msg0, line0, col0), &SyntaxError(msg1, line1, col1)) => + msg0 == msg1 && line0 == line1 && col0 == col1, + (&IoError(_), _) => false, + (_, &IoError(_)) => false, + } + } } // Builder and Parser have the same errors. pub type BuilderError = ParserError; -#[derive(Clone, PartialEq, Debug)] +#[derive(PartialEq, Debug)] pub enum DecoderError { ParseError(ParserError), ExpectedError(string::String, string::String), MissingFieldError(string::String), UnknownVariantError(string::String), - ApplicationError(string::String) + ApplicationError(string::String), + EOF, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Debug)] pub enum EncoderError { FmtError(fmt::Error), BadHashmapKey, } +impl Clone for EncoderError { + fn clone(&self) -> Self { *self } +} + /// Returns a readable error string for a given error code. pub fn error_str(error: ErrorCode) -> &'static str { match error { @@ -298,6 +349,7 @@ pub fn error_str(error: ErrorCode) -> &'static str { InvalidEscape => "invalid escape", UnrecognizedHex => "invalid \\u{ esc}ape (unrecognized hex)", NotFourDigit => "invalid \\u{ esc}ape (not four digits)", + ControlCharacterInString => "unescaped control character in string", NotUtf8 => "contents not utf-8", InvalidUnicodeCodePoint => "invalid Unicode code point", LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape", @@ -307,7 +359,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 { - let json = match from_str(s) { + let json = match Json::from_str(s) { Ok(x) => x, Err(e) => return Err(ParseError(e)) }; @@ -317,7 +369,7 @@ pub fn decode(s: &str) -> DecodeResult { } /// Shortcut function to encode a `T` into a JSON `String` -pub fn encode(object: &T) -> Result { +pub fn encode(object: &T) -> EncodeResult { let mut s = String::new(); { let mut encoder = Encoder::new(&mut s); @@ -326,53 +378,68 @@ pub fn encode(object: &T) -> Result fmt::Result { error_str(*self).fmt(f) } } -fn io_error_to_error(io: io::Error) -> ParserError { - IoError(io.kind(), io.to_string()) +impl StdError for DecoderError { + fn description(&self) -> &str { "decoder error" } + fn cause(&self) -> Option<&StdError> { + match *self { + DecoderError::ParseError(ref e) => Some(e), + _ => None, + } + } } -impl fmt::Display for ParserError { +impl fmt::Display for DecoderError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // FIXME this should be a nicer error - fmt::Debug::fmt(self, f) + fmt::Debug::fmt(&self, f) } } -impl fmt::Display for DecoderError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // FIXME this should be a nicer error - fmt::Debug::fmt(self, f) +impl From for DecoderError { + fn from(err: ParserError) -> DecoderError { + ParseError(From::from(err)) } } -impl std::error::Error for DecoderError { - fn description(&self) -> &str { "decoder error" } +impl StdError for ParserError { + fn description(&self) -> &str { "failed to parse json" } } -impl fmt::Display for EncoderError { +impl fmt::Display for ParserError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // FIXME this should be a nicer error - fmt::Debug::fmt(self, f) + fmt::Debug::fmt(&self, f) + } +} + +impl From for ParserError { + fn from(err: io::Error) -> ParserError { + IoError(err) } } -impl std::error::Error for EncoderError { +impl StdError for EncoderError { fn description(&self) -> &str { "encoder error" } } +impl fmt::Display for EncoderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self, f) + } +} + impl From for EncoderError { fn from(err: fmt::Error) -> EncoderError { EncoderError::FmtError(err) } } -pub type EncodeResult = Result<(), EncoderError>; +pub type EncodeResult = Result; pub type DecodeResult = Result; -fn escape_str(wr: &mut fmt::Write, v: &str) -> EncodeResult { +fn escape_str(wr: &mut fmt::Write, v: &str) -> EncodeResult<()> { try!(wr.write_str("\"")); let mut start = 0; @@ -434,14 +501,15 @@ fn escape_str(wr: &mut fmt::Write, v: &str) -> EncodeResult { Ok(()) } -fn escape_char(writer: &mut fmt::Write, v: char) -> EncodeResult { +fn escape_char(writer: &mut fmt::Write, v: char) -> EncodeResult<()> { let mut buf = [0; 4]; - let n = v.encode_utf8(&mut buf).unwrap(); - let buf = unsafe { str::from_utf8_unchecked(&buf[..n]) }; + let _ = write!(&mut &mut buf[..], "{}", v); + let buf = unsafe { str::from_utf8_unchecked(&buf[..v.len_utf8()]) }; escape_str(writer, buf) } -fn spaces(wr: &mut fmt::Write, mut n: usize) -> EncodeResult { +fn spaces(wr: &mut fmt::Write, n: u32) -> EncodeResult<()> { + let mut n = n as usize; const BUF: &'static str = " "; while n >= BUF.len() { @@ -456,24 +524,14 @@ fn spaces(wr: &mut fmt::Write, mut n: usize) -> EncodeResult { } 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 => v.to_string(), - _ => v.to_string() + ".0", - } -} - -/// A structure for implementing serialization to JSON. -pub struct Encoder<'a> { - writer: &'a mut (fmt::Write+'a), - is_emitting_map_key: bool, -} + use std::num::FpCategory::{Nan, Infinite}; -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::Write) -> Encoder<'a> { - Encoder { writer: writer, is_emitting_map_key: false, } + match v.classify() { + Nan | Infinite => "null".to_string(), + _ => { + let s = v.to_string(); + if s.contains(".") {s} else {s + ".0"} + } } } @@ -489,276 +547,82 @@ macro_rules! emit_enquoted_if_mapkey { } } -impl<'a> ::Encoder for Encoder<'a> { - type Error = EncoderError; - - fn emit_nil(&mut self) -> EncodeResult { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, "null")); - Ok(()) - } - - fn emit_uint(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - - fn emit_int(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i8(&mut self, v: i8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - - fn emit_bool(&mut self, v: bool) -> EncodeResult { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if v { - try!(write!(self.writer, "true")); - } else { - try!(write!(self.writer, "false")); - } - Ok(()) - } - - fn emit_f64(&mut self, v: f64) -> EncodeResult { - emit_enquoted_if_mapkey!(self, 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: usize, - cnt: usize, - 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 { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, "{{\"variant\":")); - try!(escape_str(self.writer, name)); - try!(write!(self.writer, ",\"fields\":[")); - try!(f(self)); - try!(write!(self.writer, "]}}")); - Ok(()) - } - } - - fn emit_enum_variant_arg(&mut self, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx != 0 { - try!(write!(self.writer, ",")); - } - f(self) - } - - fn emit_enum_struct_variant(&mut self, - name: &str, - id: usize, - cnt: usize, - f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_enum_variant(name, id, cnt, f) - } - - fn emit_enum_struct_variant_field(&mut self, - _: &str, - idx: usize, - f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct(&mut self, _: &str, _: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, "{{")); - try!(f(self)); - try!(write!(self.writer, "}}")); - Ok(()) - } - - fn emit_struct_field(&mut self, name: &str, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - 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: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_seq(len, f) - } - fn emit_tuple_arg(&mut self, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_seq_elt(idx, f) - } - - fn emit_tuple_struct(&mut self, _name: &str, len: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_seq(len, f) - } - fn emit_tuple_struct_arg(&mut self, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_seq_elt(idx, f) - } - - fn emit_option(&mut self, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - f(self) - } - fn emit_option_none(&mut self) -> EncodeResult { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_nil() - } - fn emit_option_some(&mut self, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - f(self) - } - - fn emit_seq(&mut self, _len: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, "[")); - try!(f(self)); - try!(write!(self.writer, "]")); - Ok(()) - } - - fn emit_seq_elt(&mut self, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx != 0 { - try!(write!(self.writer, ",")); - } - f(self) - } - - fn emit_map(&mut self, _len: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, "{{")); - try!(f(self)); - try!(write!(self.writer, "}}")); - Ok(()) - } - - fn emit_map_elt_key(&mut self, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx != 0 { try!(write!(self.writer, ",")) } - self.is_emitting_map_key = true; - try!(f(self)); - self.is_emitting_map_key = false; - Ok(()) - } - - fn emit_map_elt_val(&mut self, _idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, ":")); - f(self) +enum EncodingFormat { + Compact, + Pretty { + curr_indent: u32, + indent: u32 } } -/// Another encoder for JSON, but prints out human-readable JSON instead of -/// compact data -pub struct PrettyEncoder<'a> { +/// A structure for implementing serialization to JSON. +pub struct Encoder<'a> { writer: &'a mut (fmt::Write+'a), - curr_indent: usize, - indent: usize, + format : EncodingFormat, is_emitting_map_key: bool, } -impl<'a> PrettyEncoder<'a> { - /// Creates a new encoder whose output will be written to the specified writer - pub fn new(writer: &'a mut fmt::Write) -> PrettyEncoder<'a> { - PrettyEncoder { +impl<'a> Encoder<'a> { + /// Creates a new encoder whose output will be written in human-readable + /// JSON to the specified writer + pub fn new_pretty(writer: &'a mut fmt::Write) -> Encoder<'a> { + Encoder { writer: writer, - curr_indent: 0, - indent: 2, + format: EncodingFormat::Pretty { + curr_indent: 0, + indent: 2, + }, + is_emitting_map_key: false, + } + } + + /// Creates a new encoder whose output will be written in compact + /// JSON to the specified writer + pub fn new(writer: &'a mut fmt::Write) -> Encoder<'a> { + Encoder { + writer: writer, + format: EncodingFormat::Compact, is_emitting_map_key: false, } } /// Set the number of spaces to indent for each level. /// This is safe to set during encoding. - pub fn set_indent(&mut self, indent: usize) { - // 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; + pub fn set_indent(&mut self, new_indent: u32) -> Result<(), ()> { + if let EncodingFormat::Pretty{ref mut curr_indent, ref mut indent} = self.format { + // self.indent very well could be 0 so we need to use checked division. + let level = curr_indent.checked_div(*indent).unwrap_or(0); + *indent = new_indent; + *curr_indent = level * *indent; + Ok(()) + } else { + Err(()) + } } } -impl<'a> ::Encoder for PrettyEncoder<'a> { +impl<'a> ::Encoder for Encoder<'a> { type Error = EncoderError; - fn emit_nil(&mut self) -> EncodeResult { + fn emit_nil(&mut self) -> EncodeResult<()> { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } try!(write!(self.writer, "null")); Ok(()) } - fn emit_uint(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_usize(&mut self, v: usize) -> EncodeResult<()> { emit_enquoted_if_mapkey!(self, v) } + fn emit_u64(&mut self, v: u64) -> EncodeResult<()> { emit_enquoted_if_mapkey!(self, v) } + fn emit_u32(&mut self, v: u32) -> EncodeResult<()> { emit_enquoted_if_mapkey!(self, v) } + fn emit_u16(&mut self, v: u16) -> EncodeResult<()> { emit_enquoted_if_mapkey!(self, v) } + fn emit_u8(&mut self, v: u8) -> EncodeResult<()> { emit_enquoted_if_mapkey!(self, v) } - fn emit_int(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } - fn emit_i8(&mut self, v: i8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_isize(&mut self, v: isize) -> EncodeResult<()> { emit_enquoted_if_mapkey!(self, v) } + fn emit_i64(&mut self, v: i64) -> EncodeResult<()> { emit_enquoted_if_mapkey!(self, v) } + fn emit_i32(&mut self, v: i32) -> EncodeResult<()> { emit_enquoted_if_mapkey!(self, v) } + fn emit_i16(&mut self, v: i16) -> EncodeResult<()> { emit_enquoted_if_mapkey!(self, v) } + fn emit_i8(&mut self, v: i8) -> EncodeResult<()> { emit_enquoted_if_mapkey!(self, v) } - fn emit_bool(&mut self, v: bool) -> EncodeResult { + fn emit_bool(&mut self, v: bool) -> EncodeResult<()> { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if v { try!(write!(self.writer, "true")); @@ -768,22 +632,22 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { Ok(()) } - fn emit_f64(&mut self, v: f64) -> EncodeResult { + fn emit_f64(&mut self, v: f64) -> EncodeResult<()> { emit_enquoted_if_mapkey!(self, fmt_number_or_null(v)) } - fn emit_f32(&mut self, v: f32) -> EncodeResult { + fn emit_f32(&mut self, v: f32) -> EncodeResult<()> { self.emit_f64(v as f64) } - fn emit_char(&mut self, v: char) -> EncodeResult { + fn emit_char(&mut self, v: char) -> EncodeResult<()> { escape_char(self.writer, v) } - fn emit_str(&mut self, v: &str) -> EncodeResult { + 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, + fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { f(self) } @@ -793,42 +657,60 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { _id: usize, cnt: usize, f: F) - -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + -> 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 { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - 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; + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + try!(write!(self.writer, "{{\n")); + *curr_indent += indent; + try!(spaces(self.writer, *curr_indent)); + try!(write!(self.writer, "\"variant\": ")); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ",\n")); + try!(spaces(self.writer, *curr_indent)); + try!(write!(self.writer, "\"fields\": [\n")); + *curr_indent += indent; + } else { + try!(write!(self.writer, "{{\"variant\":")); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ",\"fields\":[")); + } 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)); - try!(write!(self.writer, "}}")); + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent -= indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, *curr_indent)); + *curr_indent -= indent; + try!(write!(self.writer, "]\n")); + try!(spaces(self.writer, *curr_indent)); + try!(write!(self.writer, "}}")); + } else { + try!(write!(self.writer, "]}}")); + } Ok(()) } } - fn emit_enum_variant_arg(&mut self, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_enum_variant_arg(&mut self, idx: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if idx != 0 { - try!(write!(self.writer, ",\n")); + try!(write!(self.writer, ",")); + if let EncodingFormat::Pretty{..} = self.format { + try!(write!(self.writer, "\n")); + } + } + if let EncodingFormat::Pretty{curr_indent, ..} = self.format { + try!(spaces(self.writer, curr_indent)); } - try!(spaces(self.writer, self.curr_indent)); f(self) } @@ -836,8 +718,8 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { name: &str, id: usize, cnt: usize, - f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_enum_variant(name, id, cnt, f) @@ -846,166 +728,189 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { fn emit_enum_struct_variant_field(&mut self, _: &str, idx: usize, - f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_enum_variant_arg(idx, f) } - fn emit_struct(&mut self, _: &str, len: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_struct(&mut self, _: &str, len: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if len == 0 { try!(write!(self.writer, "{{}}")); } else { try!(write!(self.writer, "{{")); - self.curr_indent += self.indent; + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent += indent; + } try!(f(self)); - self.curr_indent -= self.indent; - try!(write!(self.writer, "\n")); - try!(spaces(self.writer, self.curr_indent)); + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent -= indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, *curr_indent)); + } try!(write!(self.writer, "}}")); } Ok(()) } - fn emit_struct_field(&mut self, name: &str, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_struct_field(&mut self, name: &str, idx: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx == 0 { + if idx != 0 { + try!(write!(self.writer, ",")); + } + if let EncodingFormat::Pretty{curr_indent, ..} = self.format { try!(write!(self.writer, "\n")); - } else { - try!(write!(self.writer, ",\n")); + try!(spaces(self.writer, curr_indent)); } - try!(spaces(self.writer, self.curr_indent)); try!(escape_str(self.writer, name)); - try!(write!(self.writer, ": ")); + if let EncodingFormat::Pretty{..} = self.format { + try!(write!(self.writer, ": ")); + } else { + try!(write!(self.writer, ":")); + } f(self) } - fn emit_tuple(&mut self, len: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_tuple(&mut self, len: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq(len, f) } - fn emit_tuple_arg(&mut self, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_tuple_arg(&mut self, idx: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq_elt(idx, f) } - fn emit_tuple_struct(&mut self, _: &str, len: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_tuple_struct(&mut self, _: &str, len: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq(len, f) } - fn emit_tuple_struct_arg(&mut self, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_tuple_struct_arg(&mut self, idx: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_seq_elt(idx, f) } - fn emit_option(&mut self, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_option(&mut self, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } f(self) } - fn emit_option_none(&mut self) -> EncodeResult { + fn emit_option_none(&mut self) -> EncodeResult<()> { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } self.emit_nil() } - fn emit_option_some(&mut self, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_option_some(&mut self, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } f(self) } - fn emit_seq(&mut self, len: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_seq(&mut self, len: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if len == 0 { try!(write!(self.writer, "[]")); } else { try!(write!(self.writer, "[")); - self.curr_indent += self.indent; + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent += indent; + } try!(f(self)); - self.curr_indent -= self.indent; - try!(write!(self.writer, "\n")); - try!(spaces(self.writer, self.curr_indent)); + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent -= indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, *curr_indent)); + } try!(write!(self.writer, "]")); } Ok(()) } - fn emit_seq_elt(&mut self, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_seq_elt(&mut self, idx: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx == 0 { + if idx != 0 { + try!(write!(self.writer, ",")); + } + if let EncodingFormat::Pretty{ref mut curr_indent, ..} = self.format { try!(write!(self.writer, "\n")); - } else { - try!(write!(self.writer, ",\n")); + try!(spaces(self.writer, *curr_indent)); } - try!(spaces(self.writer, self.curr_indent)); f(self) } - fn emit_map(&mut self, len: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_map(&mut self, len: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } if len == 0 { try!(write!(self.writer, "{{}}")); } else { try!(write!(self.writer, "{{")); - self.curr_indent += self.indent; + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent += indent; + } try!(f(self)); - self.curr_indent -= self.indent; - try!(write!(self.writer, "\n")); - try!(spaces(self.writer, self.curr_indent)); + if let EncodingFormat::Pretty{ref mut curr_indent, indent} = self.format { + *curr_indent -= indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, *curr_indent)); + } try!(write!(self.writer, "}}")); } Ok(()) } - fn emit_map_elt_key(&mut self, idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_map_elt_key(&mut self, idx: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx == 0 { + if idx != 0 { + try!(write!(self.writer, ",")); + } + if let EncodingFormat::Pretty{curr_indent, ..} = self.format { try!(write!(self.writer, "\n")); - } else { - try!(write!(self.writer, ",\n")); + try!(spaces(self.writer, curr_indent)); } - try!(spaces(self.writer, self.curr_indent)); self.is_emitting_map_key = true; try!(f(self)); self.is_emitting_map_key = false; Ok(()) } - fn emit_map_elt_val(&mut self, _idx: usize, f: F) -> EncodeResult where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + fn emit_map_elt_val(&mut self, _idx: usize, f: F) -> EncodeResult<()> where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult<()>, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - try!(write!(self.writer, ": ")); + if let EncodingFormat::Pretty{..} = self.format { + try!(write!(self.writer, ": ")); + } else { + try!(write!(self.writer, ":")); + } f(self) } } impl Encodable for Json { - fn encode(&self, e: &mut E) -> Result<(), E::Error> { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { match *self { Json::I64(v) => v.encode(e), Json::U64(v) => v.encode(e), @@ -1021,17 +926,38 @@ impl Encodable for Json { /// 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 { +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 { +pub fn as_pretty_json(t: &T) -> AsPrettyJson { AsPrettyJson { inner: t, indent: None } } impl Json { + /// Decodes a json value from an `&mut io::Read` + pub fn from_reader(rdr: &mut io::Read) -> Result { + let contents = { + let mut c = Vec::new(); + try!(rdr.read_to_end(&mut c)); + c + }; + let s = match str::from_utf8(&contents).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() + } + /// Borrow this json object as a pretty object to generate a pretty /// representation for it via `Display`. pub fn pretty(&self) -> PrettyJson { @@ -1052,7 +978,7 @@ impl Json { /// 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 { + for key in keys.iter() { match target.find(*key) { Some(t) => { target = t; }, None => return None @@ -1070,7 +996,7 @@ impl Json { match map.get(key) { Some(json_value) => Some(json_value), None => { - for (_, v) in map { + for (_, v) in map.iter() { match v.search(key) { x if x.is_some() => return x, _ => () @@ -1098,6 +1024,15 @@ impl Json { } } + /// If the Json value is an Object, returns the associated mutable BTreeMap. + /// Returns None otherwise. + pub fn as_object_mut<'a>(&'a mut self) -> Option<&'a mut Object> { + match self { + &mut Json::Object(ref mut 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() @@ -1112,6 +1047,15 @@ impl Json { } } + /// If the Json value is an Array, returns the associated mutable vector. + /// Returns None otherwise. + pub fn as_array_mut<'a>(&'a mut self) -> Option<&'a mut Array> { + match self { + &mut Json::Array(ref mut list) => Some(list), + _ => 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() @@ -1121,7 +1065,7 @@ impl Json { /// Returns None otherwise. pub fn as_string<'a>(&'a self) -> Option<&'a str> { match *self { - Json::String(ref s) => Some(&s[..]), + Json::String(ref s) => Some(&s), _ => None } } @@ -1163,6 +1107,7 @@ impl Json { pub fn as_i64(&self) -> Option { match *self { Json::I64(n) => Some(n), + Json::U64(n) if n >= i64::MAX as u64 => None, Json::U64(n) => Some(n as i64), _ => None } @@ -1172,7 +1117,7 @@ impl Json { /// Returns None otherwise. pub fn as_u64(&self) -> Option { match *self { - Json::I64(n) => Some(n as u64), + Json::I64(n) if n >= 0 => Some(n as u64), Json::U64(n) => Some(n), _ => None } @@ -1221,7 +1166,7 @@ impl Json { impl<'a> Index<&'a str> for Json { type Output = Json; - fn index(&self, idx: &'a str) -> &Json { + fn index(&self, idx: &str) -> &Json { self.find(idx).unwrap() } } @@ -1238,7 +1183,7 @@ impl Index for Json { } /// The output of the streaming parser. -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Debug)] pub enum JsonEvent { ObjectStart, ObjectEnd, @@ -1280,8 +1225,7 @@ pub struct Stack { } /// StackElements compose a Stack. -/// For example, StackElement::Key("foo"), StackElement::Key("bar"), -/// StackElement::Index(3) and StackElement::Key("x") are the +/// 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, Debug)] pub enum StackElement<'l> { @@ -1316,8 +1260,7 @@ impl Stack { InternalIndex(i) => StackElement::Index(i), InternalKey(start, size) => { StackElement::Key(str::from_utf8( - &self.str_buffer[start as usize .. start as usize + size as usize]) - .unwrap()) + &self.str_buffer[start as usize .. start as usize + size as usize]).unwrap()) } } } @@ -1365,15 +1308,15 @@ impl Stack { } } - // Used by Parser to insert StackElement::Key elements at the top of the stack. + // 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() { + for c in key.as_bytes().iter() { self.str_buffer.push(*c); } } - // Used by Parser to insert StackElement::Index elements at the top of the stack. + // 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)); } @@ -1425,7 +1368,7 @@ pub struct Parser { state: ParserState, } -impl> Iterator for Parser { +impl> Iterator for Parser { type Item = JsonEvent; fn next(&mut self) -> Option { @@ -1448,7 +1391,7 @@ impl> Iterator for Parser { } } -impl> Parser { +impl> Parser { /// Creates the JSON parser. pub fn new(rdr: T) -> Parser { let mut p = Parser { @@ -1490,7 +1433,7 @@ impl> Parser { self.ch == Some(c) } - fn error(&self, reason: ErrorCode) -> Result { + fn error(&self, reason: ErrorCode) -> Result { Err(SyntaxError(reason, self.line, self.col)) } @@ -1538,13 +1481,11 @@ impl> Parser { F64Value(res) } else { if neg { - let res = (res as i64).wrapping_neg(); - - // Make sure we didn't underflow. - if res > 0 { + // Make sure we don't underflow. + if res > (i64::MAX as u64) + 1 { Error(SyntaxError(InvalidNumber, self.line, self.col)) } else { - I64Value(res) + I64Value((!res + 1) as i64) } } else { U64Value(res) @@ -1552,10 +1493,8 @@ impl> Parser { } } - #[allow(deprecated)] // possible resolve bug is mapping these to traits fn parse_u64(&mut self) -> Result { - let mut accum = 0u64; - let last_accum = 0; // necessary to detect overflow. + let mut accum: u64 = 0; match self.ch_or_null() { '0' => { @@ -1571,11 +1510,16 @@ impl> Parser { while !self.eof() { match self.ch_or_null() { c @ '0' ... '9' => { - accum = accum.wrapping_mul(10); - accum = accum.wrapping_add((c as u64) - ('0' as u64)); - - // Detect overflow by comparing to the last value. - if accum <= last_accum { return self.error(InvalidNumber); } + macro_rules! try_or_invalid { + ($e: expr) => { + match $e { + Some(v) => v, + None => return self.error(InvalidNumber) + } + } + } + accum = try_or_invalid!(accum.checked_mul(10)); + accum = try_or_invalid!(accum.checked_add((c as u64) - ('0' as u64))); self.bump(); } @@ -1656,27 +1600,18 @@ impl> Parser { fn decode_hex_escape(&mut self) -> Result { let mut i = 0; let mut n = 0; - while i < 4 && !self.eof() { + while i < 4 { 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, + c @ 'a' ... 'f' => n * 16 + (10 + (c as u16) - ('a' as u16)), + c @ 'A' ... 'F' => n * 16 + (10 + (c as u16) - ('A' as u16)), _ => return self.error(InvalidEscape) }; i += 1; } - // Error out if we didn't parse 4 digits. - if i != 4 { - return self.error(InvalidEscape); - } - Ok(n) } @@ -1713,11 +1648,13 @@ impl> Parser { _ => 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), + let n2 = try!(self.decode_hex_escape()); + if n2 < 0xDC00 || n2 > 0xDFFF { + return self.error(LoneLeadingSurrogateInHexEscape) } + let c = (((n1 - 0xD800) as u32) << 10 | + (n2 - 0xDC00) as u32) + 0x1_0000; + res.push(char::from_u32(c).unwrap()); } n => match char::from_u32(n as u32) { @@ -1736,6 +1673,8 @@ impl> Parser { self.bump(); return Ok(res); }, + Some(c) if c.is_control() => + return self.error(ControlCharacterInString), Some(c) => res.push(c), None => unreachable!() } @@ -1747,7 +1686,7 @@ impl> Parser { // 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 isize the form of a stack that can be queried by the user using the + // stream int the form of a stack that can be queried by the user using the // stack() method. fn parse(&mut self) -> JsonEvent { loop { @@ -1971,7 +1910,7 @@ pub struct Builder { token: Option, } -impl> Builder { +impl> Builder { /// Create a JSON Builder. pub fn new(src: T) -> Builder { Builder { parser: Parser::new(src), token: None, } @@ -1982,10 +1921,10 @@ impl> Builder { self.bump(); let result = self.build_value(); self.bump(); - match self.token { + match self.token.take() { None => {} - Some(Error(ref e)) => { return Err(e.clone()); } - ref tok => { panic!("unexpected token {:?}", tok.clone()); } + Some(Error(e)) => { return Err(e); } + ref tok => { panic!("unexpected token {:?}", tok); } } result } @@ -1995,7 +1934,7 @@ impl> Builder { } fn build_value(&mut self) -> Result { - return match self.token { + return match self.token.take() { Some(NullValue) => Ok(Json::Null), Some(I64Value(n)) => Ok(Json::I64(n)), Some(U64Value(n)) => Ok(Json::U64(n)), @@ -2006,7 +1945,7 @@ impl> Builder { swap(s, &mut temp); Ok(Json::String(temp)) } - Some(Error(ref e)) => Err(e.clone()), + Some(Error(e)) => Err(e), Some(ArrayStart) => self.build_array(), Some(ObjectStart) => self.build_object(), Some(ObjectEnd) => self.parser.error(InvalidSyntax), @@ -2020,7 +1959,7 @@ impl> Builder { let mut values = Vec::new(); loop { - if self.token == Some(ArrayEnd) { + if let Some(ArrayEnd) = self.token { return Ok(Json::Array(values.into_iter().collect())); } match self.build_value() { @@ -2037,11 +1976,11 @@ impl> Builder { let mut values = BTreeMap::new(); loop { - match self.token { + match self.token.take() { Some(ObjectEnd) => { return Ok(Json::Object(values)); } - Some(Error(ref e)) => { return Err(e.clone()); } + Some(Error(e)) => { return Err(e); } None => { break; } - _ => {} + token => { self.token = token; } } let key = match self.parser.stack().top() { Some(StackElement::Key(k)) => { k.to_string() } @@ -2057,27 +1996,6 @@ impl> Builder { } } -/// Decodes a json value from an `&mut io::Read` -pub fn from_reader(rdr: &mut Read) -> Result { - let mut contents = Vec::new(); - match rdr.read_to_end(&mut contents) { - Ok(c) => c, - Err(e) => return Err(io_error_to_error(e)) - }; - let s = match str::from_utf8(&contents).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, @@ -2091,21 +2009,24 @@ impl Decoder { } impl Decoder { - fn pop(&mut self) -> Json { - self.stack.pop().unwrap() + fn pop(&mut self) -> DecodeResult { + match self.stack.pop() { + Some(s) => Ok(s), + None => Err(EOF), + } } } macro_rules! expect { ($e:expr, Null) => ({ - match $e { + match try!($e) { Json::Null => Ok(()), other => Err(ExpectedError("Null".to_string(), format!("{}", other))) } }); ($e:expr, $t:ident) => ({ - match $e { + match try!($e) { Json::$t(v) => Ok(v), other => { Err(ExpectedError(stringify!($t).to_string(), @@ -2116,19 +2037,38 @@ macro_rules! expect { } macro_rules! read_primitive { - ($name:ident, $ty:ty) => { + ($name:ident, $ty:ident) => { + #[allow(unused_comparisons)] fn $name(&mut self) -> DecodeResult<$ty> { - match self.pop() { - Json::I64(f) => Ok(f as $ty), - Json::U64(f) => Ok(f as $ty), - Json::F64(f) => Err(ExpectedError("Integer".to_string(), format!("{}", f))), + match try!(self.pop()) { + Json::I64(i) => { + let other = i as $ty; + if i == other as i64 && (other > 0) == (i > 0) { + Ok(other) + } else { + Err(ExpectedError("Number".to_string(), i.to_string())) + } + } + Json::U64(u) => { + let other = u as $ty; + if u == other as u64 && other >= 0 { + Ok(other) + } else { + Err(ExpectedError("Number".to_string(), u.to_string())) + } + } + Json::F64(f) => { + Err(ExpectedError("Integer".to_string(), f.to_string())) + } // 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().ok() { - Some(f) => Ok(f), - None => Err(ExpectedError("Number".to_string(), s)), + Json::String(s) => match s.parse() { + Ok(f) => Ok(f), + Err(_) => Err(ExpectedError("Number".to_string(), s)), }, - value => Err(ExpectedError("Number".to_string(), format!("{}", value))), + value => { + Err(ExpectedError("Number".to_string(), value.to_string())) + } } } } @@ -2141,30 +2081,32 @@ impl ::Decoder for Decoder { expect!(self.pop(), Null) } - read_primitive! { read_uint, usize } + read_primitive! { read_usize, usize } read_primitive! { read_u8, u8 } read_primitive! { read_u16, u16 } read_primitive! { read_u32, u32 } read_primitive! { read_u64, u64 } - read_primitive! { read_int, isize } + read_primitive! { read_isize, isize } 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_f32(&mut self) -> DecodeResult { + self.read_f64().map(|x| x as f32) + } fn read_f64(&mut self) -> DecodeResult { - match self.pop() { + match try!(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().ok() { - Some(f) => Ok(f), - None => Err(ExpectedError("Number".to_string(), s)), + match s.parse() { + Ok(f) => Ok(f), + Err(_) => Err(ExpectedError("Number".to_string(), s)), } }, Json::Null => Ok(f64::NAN), @@ -2203,7 +2145,7 @@ impl ::Decoder for Decoder { mut f: F) -> DecodeResult where F: FnMut(&mut Decoder, usize) -> DecodeResult, { - let name = match self.pop() { + let name = match try!(self.pop()) { Json::String(s) => s, Json::Object(mut o) => { let n = match o.remove(&"variant".to_string()) { @@ -2234,7 +2176,7 @@ impl ::Decoder for Decoder { return Err(ExpectedError("String or Object".to_string(), format!("{}", json))) } }; - let idx = match names.iter().position(|n| *n == &name[..]) { + let idx = match names.iter().position(|n| *n == name) { Some(idx) => idx, None => return Err(UnknownVariantError(name)) }; @@ -2268,7 +2210,7 @@ impl ::Decoder for Decoder { F: FnOnce(&mut Decoder) -> DecodeResult, { let value = try!(f(self)); - self.pop(); + try!(self.pop()); Ok(value) } @@ -2340,7 +2282,7 @@ impl ::Decoder for Decoder { fn read_option(&mut self, mut f: F) -> DecodeResult where F: FnMut(&mut Decoder, bool) -> DecodeResult, { - match self.pop() { + match try!(self.pop()) { Json::Null => f(self, false), value => { self.stack.push(value); f(self, true) } } @@ -2368,7 +2310,7 @@ impl ::Decoder for Decoder { { let obj = try!(expect!(self.pop(), Object)); let len = obj.len(); - for (key, value) in obj { + for (key, value) in obj.into_iter() { self.stack.push(value); self.stack.push(Json::String(key)); } @@ -2401,9 +2343,7 @@ pub trait ToJson { macro_rules! to_json_impl_i64 { ($($t:ty), +) => ( $(impl ToJson for $t { - fn to_json(&self) -> Json { - Json::I64(*self as i64) - } + fn to_json(&self) -> Json { Json::I64(*self as i64) } })+ ) } @@ -2413,9 +2353,7 @@ to_json_impl_i64! { isize, 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) - } + fn to_json(&self) -> Json { Json::U64(*self as u64) } })+ ) } @@ -2432,8 +2370,10 @@ impl ToJson for f32 { impl ToJson for f64 { fn to_json(&self) -> Json { + use std::num::FpCategory::{Nan, Infinite}; + match self.classify() { - Fp::Nan | Fp::Infinite => Json::Null, + Nan | Infinite => Json::Null, _ => Json::F64(*self) } } @@ -2498,7 +2438,7 @@ impl ToJson for Vec { impl ToJson for BTreeMap { fn to_json(&self) -> Json { let mut d = BTreeMap::new(); - for (key, value) in self { + for (key, value) in self.iter() { d.insert((*key).clone(), value.to_json()); } Json::Object(d) @@ -2508,7 +2448,7 @@ impl ToJson for BTreeMap { impl ToJson for HashMap { fn to_json(&self) -> Json { let mut d = BTreeMap::new(); - for (key, value) in self { + for (key, value) in self.iter() { d.insert((*key).clone(), value.to_json()); } Json::Object(d) @@ -2553,7 +2493,7 @@ impl<'a> fmt::Display 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); + let mut encoder = Encoder::new_pretty(&mut shim); match self.inner.encode(&mut encoder) { Ok(_) => Ok(()), Err(_) => Err(fmt::Error) @@ -2575,7 +2515,7 @@ impl<'a, T: Encodable> fmt::Display for AsJson<'a, T> { impl<'a, T> AsPrettyJson<'a, T> { /// Set the indentation level for the emitted JSON - pub fn indent(mut self, indent: usize) -> AsPrettyJson<'a, T> { + pub fn indent(mut self, indent: u32) -> AsPrettyJson<'a, T> { self.indent = Some(indent); self } @@ -2585,10 +2525,10 @@ impl<'a, T: Encodable> fmt::Display 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 }; - let mut encoder = PrettyEncoder::new(&mut shim); - match self.indent { - Some(n) => encoder.set_indent(n), - None => {} + let mut encoder = Encoder::new_pretty(&mut shim); + if let Some(n) = self.indent { + // unwrap cannot panic for pretty encoders + let _ = encoder.set_indent(n); } match self.inner.encode(&mut encoder) { Ok(_) => Ok(()), @@ -2598,28 +2538,26 @@ impl<'a, T: Encodable> fmt::Display for AsPrettyJson<'a, T> { } impl FromStr for Json { - type Err = BuilderError; - fn from_str(s: &str) -> Result { - from_str(s) + type Err = ParserError; + fn from_str(s: &str) -> Result { + Json::from_str(s) } } #[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::{Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser, + use super::StackElement::*; + use super::{Json, DecodeResult, DecoderError, JsonEvent, Parser, StackElement, Stack, Decoder, Encoder, EncoderError}; use std::{i64, u64, f32, f64}; - use std::io::prelude::*; use std::collections::BTreeMap; use std::string; @@ -2671,7 +2609,7 @@ mod tests { fn mk_object(items: &[(string::String, Json)]) -> Json { let mut d = BTreeMap::new(); - for item in items { + for item in items.iter() { match *item { (ref key, ref value) => { d.insert((*key).clone(), (*value).clone()); }, } @@ -2911,29 +2849,29 @@ mod tests { #[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))); + assert_eq!(Json::from_str("nulla"), Err(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(Json::from_str("truea"), Err(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(Json::from_str("falsea"), Err(SyntaxError(TrailingCharacters, 1, 6))); + assert_eq!(Json::from_str("1a"), Err(SyntaxError(TrailingCharacters, 1, 2))); + assert_eq!(Json::from_str("[]a"), Err(SyntaxError(TrailingCharacters, 1, 3))); + assert_eq!(Json::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!(Json::from_str("n"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(Json::from_str("nul"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(Json::from_str("t"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(Json::from_str("truz"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(Json::from_str("f"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(Json::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))); + assert_eq!(Json::from_str("null"), Ok(Null)); + assert_eq!(Json::from_str("true"), Ok(Boolean(true))); + assert_eq!(Json::from_str("false"), Ok(Boolean(false))); + assert_eq!(Json::from_str(" null "), Ok(Null)); + assert_eq!(Json::from_str(" true "), Ok(Boolean(true))); + assert_eq!(Json::from_str(" false "), Ok(Boolean(false))); } #[test] @@ -2950,30 +2888,31 @@ mod tests { #[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))); + assert_eq!(Json::from_str("+"), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(Json::from_str("."), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(Json::from_str("NaN"), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(Json::from_str("-"), Err(SyntaxError(InvalidNumber, 1, 2))); + assert_eq!(Json::from_str("00"), Err(SyntaxError(InvalidNumber, 1, 2))); + assert_eq!(Json::from_str("1."), Err(SyntaxError(InvalidNumber, 1, 3))); + assert_eq!(Json::from_str("1e"), Err(SyntaxError(InvalidNumber, 1, 3))); + assert_eq!(Json::from_str("1e+"), Err(SyntaxError(InvalidNumber, 1, 4))); + + assert_eq!(Json::from_str("18446744073709551616"), Err(SyntaxError(InvalidNumber, 1, 20))); + assert_eq!(Json::from_str("18446744073709551617"), Err(SyntaxError(InvalidNumber, 1, 20))); + assert_eq!(Json::from_str("-9223372036854775809"), Err(SyntaxError(InvalidNumber, 1, 21))); + + assert_eq!(Json::from_str("3"), Ok(U64(3))); + assert_eq!(Json::from_str("3.1"), Ok(F64(3.1))); + assert_eq!(Json::from_str("-1.2"), Ok(F64(-1.2))); + assert_eq!(Json::from_str("0.4"), Ok(F64(0.4))); + assert_eq!(Json::from_str("0.4e5"), Ok(F64(0.4e5))); + assert_eq!(Json::from_str("0.4e+15"), Ok(F64(0.4e15))); + assert_eq!(Json::from_str("0.4e-01"), Ok(F64(0.4e-01))); + assert_eq!(Json::from_str(" 3 "), Ok(U64(3))); + + assert_eq!(Json::from_str("-9223372036854775808"), Ok(I64(i64::MIN))); + assert_eq!(Json::from_str("9223372036854775807"), Ok(U64(i64::MAX as u64))); + assert_eq!(Json::from_str("18446744073709551615"), Ok(U64(u64::MAX))); } #[test] @@ -3011,26 +2950,30 @@ mod tests { let v: i64 = super::decode("9223372036854775807").unwrap(); assert_eq!(v, i64::MAX); - let res: DecodeResult = super::decode("765.25"); - assert_eq!(res, Err(ExpectedError("Integer".to_string(), - "765.25".to_string()))); + let res: DecodeResult = super::decode("765.25252"); + match res { + Ok(..) => panic!("expected an error"), + Err(ExpectedError(ref s, _)) => assert_eq!(s, "Integer"), + Err(..) => panic!("expected an 'expected integer' error"), + } } #[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!(Json::from_str("\""), Err(SyntaxError(EOFWhileParsingString, 1, 2))); + assert_eq!(Json::from_str("\"lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5))); + assert_eq!(Json::from_str("\"\n\""), Err(SyntaxError(ControlCharacterInString, 2, 1))); - 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()))); + assert_eq!(Json::from_str("\"\""), Ok(String("".to_string()))); + assert_eq!(Json::from_str("\"foo\""), Ok(String("foo".to_string()))); + assert_eq!(Json::from_str("\"\\\"\""), Ok(String("\"".to_string()))); + assert_eq!(Json::from_str("\"\\b\""), Ok(String("\x08".to_string()))); + assert_eq!(Json::from_str("\"\\n\""), Ok(String("\n".to_string()))); + assert_eq!(Json::from_str("\"\\r\""), Ok(String("\r".to_string()))); + assert_eq!(Json::from_str("\"\\t\""), Ok(String("\t".to_string()))); + assert_eq!(Json::from_str(" \"foo\" "), Ok(String("foo".to_string()))); + assert_eq!(Json::from_str("\"\\u12ab\""), Ok(String("\u{12ab}".to_string()))); + assert_eq!(Json::from_str("\"\\uAB12\""), Ok(String("\u{AB12}".to_string()))); } #[test] @@ -3045,7 +2988,7 @@ mod tests { ("\"\\u12ab\"", "\u{12ab}"), ("\"\\uAB12\"", "\u{AB12}")]; - for &(i, o) in &s { + for &(i, o) in s.iter() { let v: string::String = super::decode(i).unwrap(); assert_eq!(v, o); } @@ -3053,41 +2996,41 @@ mod tests { #[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]"), + assert_eq!(Json::from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2))); + assert_eq!(Json::from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3))); + assert_eq!(Json::from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4))); + assert_eq!(Json::from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(Json::from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + + assert_eq!(Json::from_str("[]"), Ok(Array(vec![]))); + assert_eq!(Json::from_str("[ ]"), Ok(Array(vec![]))); + assert_eq!(Json::from_str("[true]"), Ok(Array(vec![Boolean(true)]))); + assert_eq!(Json::from_str("[ false ]"), Ok(Array(vec![Boolean(false)]))); + assert_eq!(Json::from_str("[null]"), Ok(Array(vec![Null]))); + assert_eq!(Json::from_str("[3, 1]"), Ok(Array(vec![U64(3), U64(1)]))); - assert_eq!(from_str("\n[3, 2]\n"), + assert_eq!(Json::from_str("\n[3, 2]\n"), Ok(Array(vec![U64(3), U64(2)]))); - assert_eq!(from_str("[2, [4, 1]]"), + assert_eq!(Json::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, []); + assert_eq!(v, vec![]); let v: Vec<()> = super::decode("[null]").unwrap(); - assert_eq!(v, [()]); + assert_eq!(v, vec![()]); let v: Vec = super::decode("[true]").unwrap(); - assert_eq!(v, [true]); + assert_eq!(v, vec![true]); let v: Vec = super::decode("[3, 1]").unwrap(); - assert_eq!(v, [3, 1]); + assert_eq!(v, vec![3, 1]); let v: Vec> = super::decode("[[3], [1, 2]]").unwrap(); - assert_eq!(v, [vec![3], vec![1, 2]]); + assert_eq!(v, vec![vec![3], vec![1, 2]]); } #[test] @@ -3111,39 +3054,39 @@ mod tests { #[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(), + assert_eq!(Json::from_str("{"), Err(SyntaxError(EOFWhileParsingObject, 1, 2))); + assert_eq!(Json::from_str("{ "), Err(SyntaxError(EOFWhileParsingObject, 1, 3))); + assert_eq!(Json::from_str("{1"), Err(SyntaxError(KeyMustBeAString, 1, 2))); + assert_eq!(Json::from_str("{ \"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 6))); + assert_eq!(Json::from_str("{\"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 5))); + assert_eq!(Json::from_str("{\"a\" "), Err(SyntaxError(EOFWhileParsingObject, 1, 6))); + + assert_eq!(Json::from_str("{\"a\" 1"), Err(SyntaxError(ExpectedColon, 1, 6))); + assert_eq!(Json::from_str("{\"a\":"), Err(SyntaxError(EOFWhileParsingValue, 1, 6))); + assert_eq!(Json::from_str("{\"a\":1"), Err(SyntaxError(EOFWhileParsingObject, 1, 7))); + assert_eq!(Json::from_str("{\"a\":1 1"), Err(SyntaxError(InvalidSyntax, 1, 8))); + assert_eq!(Json::from_str("{\"a\":1,"), Err(SyntaxError(EOFWhileParsingObject, 1, 8))); + + assert_eq!(Json::from_str("{}").unwrap(), mk_object(&[])); + assert_eq!(Json::from_str("{\"a\": 3}").unwrap(), mk_object(&[("a".to_string(), U64(3))])); - assert_eq!(from_str( + assert_eq!(Json::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(), + assert_eq!(Json::from_str("\n{ \"a\": null, \"b\" : true }\n").unwrap(), mk_object(&[ ("a".to_string(), Null), ("b".to_string(), Boolean(true))])); - assert_eq!(from_str( + assert_eq!(Json::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( + assert_eq!(Json::from_str( "{\ \"a\": 1.0, \ \"b\": [\ @@ -3228,7 +3171,7 @@ mod tests { #[test] fn test_multiline_errors() { - assert_eq!(from_str("{\n \"foo\":\n \"bar\""), + assert_eq!(Json::from_str("{\n \"foo\":\n \"bar\""), Err(SyntaxError(EOFWhileParsingObject, 3, 8))); } @@ -3246,14 +3189,14 @@ mod tests { B(string::String) } fn check_err(to_parse: &'static str, expected: DecoderError) { - let res: DecodeResult = match from_str(to_parse) { + let res: DecodeResult = match Json::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: {:?}", + Err(ParseError(e)) => panic!("`{}` is not valid json: {:?}", to_parse, e), Err(e) => { assert_eq!(e, expected); @@ -3290,28 +3233,28 @@ mod tests { #[test] fn test_find(){ - let json_value = from_str("{\"dog\" : \"cat\"}").unwrap(); + let json_value = Json::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 json_value = Json::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 json_value = Json::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 json_value = Json::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"); @@ -3320,26 +3263,26 @@ mod tests { #[test] fn test_is_object(){ - let json_value = from_str("{}").unwrap(); + let json_value = Json::from_str("{}").unwrap(); assert!(json_value.is_object()); } #[test] fn test_as_object(){ - let json_value = from_str("{}").unwrap(); + let json_value = Json::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(); + let json_value = Json::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_value = Json::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); @@ -3347,13 +3290,13 @@ mod tests { #[test] fn test_is_string(){ - let json_value = from_str("\"dog\"").unwrap(); + let json_value = Json::from_str("\"dog\"").unwrap(); assert!(json_value.is_string()); } #[test] fn test_as_string(){ - let json_value = from_str("\"dog\"").unwrap(); + let json_value = Json::from_str("\"dog\"").unwrap(); let json_str = json_value.as_string(); let expected_str = "dog"; assert_eq!(json_str, Some(expected_str)); @@ -3361,79 +3304,79 @@ mod tests { #[test] fn test_is_number(){ - let json_value = from_str("12").unwrap(); + let json_value = Json::from_str("12").unwrap(); assert!(json_value.is_number()); } #[test] fn test_is_i64(){ - let json_value = from_str("-12").unwrap(); + let json_value = Json::from_str("-12").unwrap(); assert!(json_value.is_i64()); - let json_value = from_str("12").unwrap(); + let json_value = Json::from_str("12").unwrap(); assert!(!json_value.is_i64()); - let json_value = from_str("12.0").unwrap(); + let json_value = Json::from_str("12.0").unwrap(); assert!(!json_value.is_i64()); } #[test] fn test_is_u64(){ - let json_value = from_str("12").unwrap(); + let json_value = Json::from_str("12").unwrap(); assert!(json_value.is_u64()); - let json_value = from_str("-12").unwrap(); + let json_value = Json::from_str("-12").unwrap(); assert!(!json_value.is_u64()); - let json_value = from_str("12.0").unwrap(); + let json_value = Json::from_str("12.0").unwrap(); assert!(!json_value.is_u64()); } #[test] fn test_is_f64(){ - let json_value = from_str("12").unwrap(); + let json_value = Json::from_str("12").unwrap(); assert!(!json_value.is_f64()); - let json_value = from_str("-12").unwrap(); + let json_value = Json::from_str("-12").unwrap(); assert!(!json_value.is_f64()); - let json_value = from_str("12.0").unwrap(); + let json_value = Json::from_str("12.0").unwrap(); assert!(json_value.is_f64()); - let json_value = from_str("-12.0").unwrap(); + let json_value = Json::from_str("-12.0").unwrap(); assert!(json_value.is_f64()); } #[test] fn test_as_i64(){ - let json_value = from_str("-12").unwrap(); + let json_value = Json::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_value = Json::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_value = Json::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(); + let json_value = Json::from_str("false").unwrap(); assert!(json_value.is_boolean()); } #[test] fn test_as_boolean(){ - let json_value = from_str("false").unwrap(); + let json_value = Json::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); @@ -3441,13 +3384,13 @@ mod tests { #[test] fn test_is_null(){ - let json_value = from_str("null").unwrap(); + let json_value = Json::from_str("null").unwrap(); assert!(json_value.is_null()); } #[test] fn test_as_null(){ - let json_value = from_str("null").unwrap(); + let json_value = Json::from_str("null").unwrap(); let json_null = json_value.as_null(); let expected_null = (); assert!(json_null.is_some() && json_null.unwrap() == expected_null); @@ -3455,37 +3398,30 @@ mod tests { #[test] fn test_encode_hashmap_with_numeric_key() { - use std::str::from_utf8; 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), + let json_str = super::as_pretty_json(&hm).to_string(); + match Json::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::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), + let json_str = super::as_pretty_json(&hm).to_string(); + match Json::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(); @@ -3512,11 +3448,8 @@ mod tests { // Test up to 4 spaces of indents (more?) for i in 0..4 { - let mut writer = Vec::new(); - write!(&mut writer, "{}", - super::as_pretty_json(&json).indent(i)).unwrap(); - - let printed = from_utf8(&writer[..]).unwrap(); + let printed = super::as_pretty_json(&json).indent(i as u32) + .to_string(); // Check for indents at each line let lines: Vec<&str> = printed.lines().collect(); @@ -3531,10 +3464,24 @@ mod tests { 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!"); + Json::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 Json::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_enum_key() { use std::collections::HashMap; @@ -3548,31 +3495,18 @@ mod tests { let mut map = HashMap::new(); map.insert(Enum::Foo, 0); let result = json::encode(&map).unwrap(); - assert_eq!(&result[..], r#"{"Foo":0}"#); + assert_eq!(result, r#"{"Foo":0}"#); let decoded: HashMap = json::decode(&result).unwrap(); assert_eq!(map, decoded); } - #[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), + let json_obj = match Json::from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), Ok(o) => o }; let mut decoder = Decoder::new(json_obj); @@ -3590,7 +3524,7 @@ mod tests { None => { break; } }; let (ref expected_evt, ref expected_stack) = expected[i]; - if !parser.stack().is_equal_to(expected_stack) { + if !parser.stack().is_equal_to(&expected_stack) { panic!("Parser stack is not equal to {:?}", expected_stack); } assert_eq!(&evt, expected_evt); @@ -3598,29 +3532,26 @@ mod tests { } } #[test] - #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064) + #[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![StackElement::Key("foo")]), - (ArrayStart, vec![StackElement::Key("array")]), - (U64Value(0), vec![StackElement::Key("array"), StackElement::Index(0)]), - (U64Value(1), vec![StackElement::Key("array"), StackElement::Index(1)]), - (U64Value(2), vec![StackElement::Key("array"), StackElement::Index(2)]), - (U64Value(3), vec![StackElement::Key("array"), StackElement::Index(3)]), - (U64Value(4), vec![StackElement::Key("array"), StackElement::Index(4)]), - (U64Value(5), vec![StackElement::Key("array"), StackElement::Index(5)]), - (ArrayEnd, vec![StackElement::Key("array")]), - (ArrayStart, vec![StackElement::Key("idents")]), - (NullValue, vec![StackElement::Key("idents"), - StackElement::Index(0)]), - (BooleanValue(true), vec![StackElement::Key("idents"), - StackElement::Index(1)]), - (BooleanValue(false), vec![StackElement::Key("idents"), - StackElement::Index(2)]), - (ArrayEnd, vec![StackElement::Key("idents")]), + (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![]), ] ); @@ -3637,7 +3568,7 @@ mod tests { } #[test] - #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064) + #[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))); @@ -3660,7 +3591,7 @@ mod tests { "{\"a\": 3}", vec![ (ObjectStart, vec![]), - (U64Value(3), vec![StackElement::Key("a")]), + (U64Value(3), vec![Key("a")]), (ObjectEnd, vec![]), ] ); @@ -3668,8 +3599,8 @@ mod tests { "{ \"a\": null, \"b\" : true }", vec![ (ObjectStart, vec![]), - (NullValue, vec![StackElement::Key("a")]), - (BooleanValue(true), vec![StackElement::Key("b")]), + (NullValue, vec![Key("a")]), + (BooleanValue(true), vec![Key("b")]), (ObjectEnd, vec![]), ] ); @@ -3677,10 +3608,10 @@ mod tests { "{\"a\" : 1.0 ,\"b\": [ true ]}", vec![ (ObjectStart, vec![]), - (F64Value(1.0), vec![StackElement::Key("a")]), - (ArrayStart, vec![StackElement::Key("b")]), - (BooleanValue(true),vec![StackElement::Key("b"), StackElement::Index(0)]), - (ArrayEnd, vec![StackElement::Key("b")]), + (F64Value(1.0), vec![Key("a")]), + (ArrayStart, vec![Key("b")]), + (BooleanValue(true),vec![Key("b"), Index(0)]), + (ArrayEnd, vec![Key("b")]), (ObjectEnd, vec![]), ] ); @@ -3690,38 +3621,29 @@ mod tests { "b": [ true, "foo\nbar", - { "c": {"d": null} } + { "c": {"d": null} }, + "\uD834\uDF06" ] }"#, vec![ (ObjectStart, vec![]), - (F64Value(1.0), vec![StackElement::Key("a")]), - (ArrayStart, vec![StackElement::Key("b")]), - (BooleanValue(true), vec![StackElement::Key("b"), - StackElement::Index(0)]), - (StringValue("foo\nbar".to_string()), vec![StackElement::Key("b"), - StackElement::Index(1)]), - (ObjectStart, vec![StackElement::Key("b"), - StackElement::Index(2)]), - (ObjectStart, vec![StackElement::Key("b"), - StackElement::Index(2), - StackElement::Key("c")]), - (NullValue, vec![StackElement::Key("b"), - StackElement::Index(2), - StackElement::Key("c"), - StackElement::Key("d")]), - (ObjectEnd, vec![StackElement::Key("b"), - StackElement::Index(2), - StackElement::Key("c")]), - (ObjectEnd, vec![StackElement::Key("b"), - StackElement::Index(2)]), - (ArrayEnd, vec![StackElement::Key("b")]), + (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)]), + (StringValue("\u{1D306}".to_string()), vec![Key("b"), Index(3)]), + (ArrayEnd, vec![Key("b")]), (ObjectEnd, vec![]), ] ); } #[test] - #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064) + #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) fn test_read_array_streaming() { assert_stream_equal( "[]", @@ -3741,7 +3663,7 @@ mod tests { "[true]", vec![ (ArrayStart, vec![]), - (BooleanValue(true), vec![StackElement::Index(0)]), + (BooleanValue(true), vec![Index(0)]), (ArrayEnd, vec![]), ] ); @@ -3749,7 +3671,7 @@ mod tests { "[ false ]", vec![ (ArrayStart, vec![]), - (BooleanValue(false), vec![StackElement::Index(0)]), + (BooleanValue(false), vec![Index(0)]), (ArrayEnd, vec![]), ] ); @@ -3757,7 +3679,7 @@ mod tests { "[null]", vec![ (ArrayStart, vec![]), - (NullValue, vec![StackElement::Index(0)]), + (NullValue, vec![Index(0)]), (ArrayEnd, vec![]), ] ); @@ -3765,8 +3687,8 @@ mod tests { "[3, 1]", vec![ (ArrayStart, vec![]), - (U64Value(3), vec![StackElement::Index(0)]), - (U64Value(1), vec![StackElement::Index(1)]), + (U64Value(3), vec![Index(0)]), + (U64Value(1), vec![Index(1)]), (ArrayEnd, vec![]), ] ); @@ -3774,8 +3696,8 @@ mod tests { "\n[3, 2]\n", vec![ (ArrayStart, vec![]), - (U64Value(3), vec![StackElement::Index(0)]), - (U64Value(2), vec![StackElement::Index(1)]), + (U64Value(3), vec![Index(0)]), + (U64Value(2), vec![Index(1)]), (ArrayEnd, vec![]), ] ); @@ -3783,22 +3705,22 @@ mod tests { "[2, [4, 1]]", vec![ (ArrayStart, vec![]), - (U64Value(2), vec![StackElement::Index(0)]), - (ArrayStart, vec![StackElement::Index(1)]), - (U64Value(4), vec![StackElement::Index(1), StackElement::Index(0)]), - (U64Value(1), vec![StackElement::Index(1), StackElement::Index(1)]), - (ArrayEnd, vec![StackElement::Index(1)]), + (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))); + assert_eq!(Json::from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2))); + assert_eq!(Json::from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3))); + assert_eq!(Json::from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4))); + assert_eq!(Json::from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(Json::from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4))); } #[test] @@ -3829,63 +3751,57 @@ mod tests { let mut stack = Stack::new(); assert!(stack.is_empty()); - 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(&[StackElement::Index(1)])); - assert!(stack.starts_with(&[StackElement::Index(1)])); - assert!(stack.ends_with(&[StackElement::Index(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) == StackElement::Index(1)); + assert!(stack.get(0) == Index(1)); stack.push_key("foo".to_string()); assert!(stack.len() == 2); - assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.starts_with(&[StackElement::Index(1)])); - assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.ends_with(&[StackElement::Key("foo")])); + 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) == StackElement::Index(1)); - assert!(stack.get(1) == StackElement::Key("foo")); + 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(&[StackElement::Index(1), - StackElement::Key("foo"), - StackElement::Key("bar")])); - assert!(stack.starts_with(&[StackElement::Index(1)])); - assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.starts_with(&[StackElement::Index(1), - StackElement::Key("foo"), - StackElement::Key("bar")])); - assert!(stack.ends_with(&[StackElement::Key("bar")])); - assert!(stack.ends_with(&[StackElement::Key("foo"), StackElement::Key("bar")])); - assert!(stack.ends_with(&[StackElement::Index(1), - StackElement::Key("foo"), - StackElement::Key("bar")])); + 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) == StackElement::Index(1)); - assert!(stack.get(1) == StackElement::Key("foo")); - assert!(stack.get(2) == StackElement::Key("bar")); + 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(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.starts_with(&[StackElement::Index(1)])); - assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")])); - assert!(stack.ends_with(&[StackElement::Key("foo")])); + 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) == StackElement::Index(1)); - assert!(stack.get(1) == StackElement::Key("foo")); + assert!(stack.get(0) == Index(1)); + assert!(stack.get(1) == Key("foo")); } #[test] @@ -3893,8 +3809,8 @@ mod tests { 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 array2 = Array(vec!(I64(1), I64(2))); + let array3 = Array(vec!(I64(1), I64(2), I64(3))); let object = { let mut tree_map = BTreeMap::new(); tree_map.insert("a".to_string(), U64(1)); @@ -3923,22 +3839,22 @@ mod tests { 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!((1_usize, 2_usize).to_json(), array2); - assert_eq!((1_usize, 2_usize, 3_usize).to_json(), array3); - assert_eq!([1_usize, 2_usize].to_json(), array2); - assert_eq!((&[1_usize, 2_usize, 3_usize]).to_json(), array3); - assert_eq!((vec![1_usize, 2_usize]).to_json(), array2); - assert_eq!(vec!(1_usize, 2_usize, 3_usize).to_json(), array3); + assert_eq!((1, 2).to_json(), array2); + assert_eq!((1, 2, 3).to_json(), array3); + assert_eq!([1, 2].to_json(), array2); + assert_eq!((&[1, 2, 3]).to_json(), array3); + assert_eq!((vec![1, 2]).to_json(), array2); + assert_eq!(vec!(1, 2, 3).to_json(), array3); let mut tree_map = BTreeMap::new(); - tree_map.insert("a".to_string(), 1 as usize); + tree_map.insert("a".to_string(), 1 as u32); 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(), 1 as usize); + hash_map.insert("a".to_string(), 1 as u32); hash_map.insert("b".to_string(), 2); assert_eq!(hash_map.to_json(), object); assert_eq!(Some(15).to_json(), I64(15)); - assert_eq!(Some(15 as usize).to_json(), U64(15)); + assert_eq!(Some(15 as u32).to_json(), U64(15)); assert_eq!(None::.to_json(), Null); } @@ -3946,7 +3862,7 @@ mod tests { fn test_encode_hashmap_with_arbitrary_key() { use std::collections::HashMap; #[derive(PartialEq, Eq, Hash, RustcEncodable)] - struct ArbitraryType(usize); + struct ArbitraryType(u32); let mut hm: HashMap = HashMap::new(); hm.insert(ArbitraryType(1), true); let mut mem_buf = string::String::new(); @@ -3958,67 +3874,33 @@ mod tests { } } - #[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 0..500 { - src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \ - [1,2,3]},"#); + #[test] + fn test_bad_json_stack_depleted() { + use json; + #[derive(Debug, RustcDecodable)] + enum ChatEvent { + Variant(i32) } - src.push_str("{}]"); - return src; + let serialized = "{\"variant\": \"Variant\", \"fields\": []}"; + let r: Result = json::decode(serialized); + assert!(r.unwrap_err() == EOF); } - #[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); }); + #[test] + fn fixed_length_array() { + #[derive(Debug, RustcDecodable, RustcEncodable, Eq, PartialEq)] + struct Foo { + a: [u8; 1], + b: [i32; 2], + c: [u64; 3], + } + let f = Foo { + a: [0], + b: [1, 2], + c: [3, 4, 5], + }; + let s = super::encode(&f).unwrap(); + let d = super::decode(&s).unwrap(); + assert_eq!(f, d); } } diff --git a/src/external/rustc_serialize/src/lib.rs b/src/external/rustc_serialize/src/lib.rs new file mode 100644 index 0000000000000..b1ebbd94bb8eb --- /dev/null +++ b/src/external/rustc_serialize/src/lib.rs @@ -0,0 +1,55 @@ +// 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. +//! +//! # Usage +//! +//! This crate is [on crates.io](https://crates.io/crates/rustc-serialize) and +//! can be used by adding `rustc-serialize` to the dependencies in your +//! project's `Cargo.toml`. +//! +//! ```toml +//! [dependencies] +//! rustc-serialize = "0.3" +//! ``` +//! +//! and this to your crate root: +//! +//! ```rust +//! extern crate rustc_serialize; +//! ``` + +#![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/rustc-serialize/")] +#![cfg_attr(test, deny(warnings))] +#![allow(trivial_numeric_casts)] +#![cfg_attr(rust_build, feature(staged_api))] +#![cfg_attr(rust_build, staged_api)] +#![cfg_attr(rust_build, + unstable(feature = "rustc_private", + reason = "use the crates.io `rustc-serialize` library instead"))] + +#[cfg(test)] extern crate rand; + +pub use self::serialize::{Decoder, Encoder, Decodable, Encodable, + DecoderHelpers, EncoderHelpers}; + +mod serialize; +mod collection_impls; + +pub mod base64; +pub mod hex; +pub mod json; + +mod rustc_serialize { + pub use serialize::*; +} diff --git a/src/libserialize/serialize.rs b/src/external/rustc_serialize/src/serialize.rs similarity index 84% rename from src/libserialize/serialize.rs rename to src/external/rustc_serialize/src/serialize.rs index af1387346106a..436226c285980 100644 --- a/src/libserialize/serialize.rs +++ b/src/external/rustc_serialize/src/serialize.rs @@ -14,22 +14,25 @@ Core encoding and decoding interfaces. */ +use std::cell::{Cell, RefCell}; +use std::ffi::OsString; use std::path; use std::rc::Rc; -use std::cell::{Cell, RefCell}; use std::sync::Arc; +use std::marker::PhantomData; +use std::borrow::Cow; pub trait Encoder { type Error; // Primitive types: fn emit_nil(&mut self) -> Result<(), Self::Error>; - fn emit_uint(&mut self, v: usize) -> Result<(), Self::Error>; + fn emit_usize(&mut self, v: usize) -> 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: isize) -> Result<(), Self::Error>; + fn emit_isize(&mut self, v: isize) -> 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>; @@ -108,12 +111,12 @@ pub trait Decoder { // Primitive types: fn read_nil(&mut self) -> Result<(), Self::Error>; - fn read_uint(&mut self) -> Result; + fn read_usize(&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_isize(&mut self) -> Result; fn read_i64(&mut self) -> Result; fn read_i32(&mut self) -> Result; fn read_i16(&mut self) -> Result; @@ -200,13 +203,13 @@ pub trait Decodable { impl Encodable for usize { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_uint(*self) + s.emit_usize(*self) } } impl Decodable for usize { fn decode(d: &mut D) -> Result { - d.read_uint() + d.read_usize() } } @@ -260,13 +263,13 @@ impl Decodable for u64 { impl Encodable for isize { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_int(*self) + s.emit_isize(*self) } } impl Decodable for isize { fn decode(d: &mut D) -> Result { - d.read_int() + d.read_isize() } } @@ -326,7 +329,7 @@ impl Encodable for str { impl Encodable for String { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_str(&self[..]) + s.emit_str(self) } } @@ -410,7 +413,7 @@ impl Encodable for Box { impl< T: Decodable> Decodable for Box { fn decode(d: &mut D) -> Result, D::Error> { - Ok(box try!(Decodable::decode(d))) + Ok(Box::new(try!(Decodable::decode(d)))) } } @@ -435,6 +438,22 @@ impl Decodable for Rc { } } +impl<'a, T:Encodable + ToOwned + ?Sized> Encodable for Cow<'a, T> { + #[inline] + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + (**self).encode(s) + } +} + +impl<'a, T: ?Sized> Decodable for Cow<'a, T> + where T: ToOwned, T::Owned: Decodable +{ + #[inline] + fn decode(d: &mut D) -> Result, D::Error> { + Ok(Cow::Owned(try!(Decodable::decode(d)))) + } +} + impl Encodable for [T] { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { @@ -492,11 +511,24 @@ impl Decodable for Option { } } +impl Encodable for PhantomData { + fn encode(&self, _s: &mut S) -> Result<(), S::Error> { + Ok(()) + } +} + +impl Decodable for PhantomData { + fn decode(_d: &mut D) -> Result, D::Error> { + Ok(PhantomData) + } +} + 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 +/// Evaluates to the number of identifiers passed to it, for example: +/// `count_idents!(a, b, c) == 3 macro_rules! count_idents { () => { 0 }; ($_i:ident, $($rest:ident,)*) => { 1 + count_idents!($($rest,)*) } @@ -506,7 +538,6 @@ macro_rules! tuple { () => (); ( $($name:ident,)+ ) => ( impl<$($name:Decodable),*> Decodable for ($($name,)*) { - #[allow(non_snake_case)] fn decode(d: &mut D) -> Result<($($name,)*), D::Error> { let len: usize = count_idents!($($name,)*); d.read_tuple(len, |d| { @@ -538,16 +569,80 @@ macro_rules! tuple { tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } +macro_rules! array { + ($zero:expr) => (); + ($len:expr, $($idx:expr),*) => { + impl Decodable for [T; $len] { + fn decode(d: &mut D) -> Result<[T; $len], D::Error> { + d.read_seq(|d, len| { + if len != $len { + return Err(d.error("wrong array length")); + } + Ok([$( + try!(d.read_seq_elt($len - $idx - 1, + |d| Decodable::decode(d))) + ),+]) + }) + } + } + + impl Encodable for [T; $len] { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_seq($len, |s| { + for i in 0..$len { + try!(s.emit_seq_elt(i, |s| self[i].encode(s))); + } + Ok(()) + }) + } + } + array! { $($idx),* } + } +} + +array! { + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +} + +impl Encodable for path::Path { + #[cfg(unix)] + fn encode(&self, e: &mut S) -> Result<(), S::Error> { + use std::os::unix::prelude::*; + self.as_os_str().as_bytes().encode(e) + } + #[cfg(windows)] + fn encode(&self, e: &mut S) -> Result<(), S::Error> { + use std::os::windows::prelude::*; + let v = self.as_os_str().encode_wide().collect::>(); + v.encode(e) + } +} + impl Encodable for path::PathBuf { fn encode(&self, e: &mut S) -> Result<(), S::Error> { - self.to_str().unwrap().encode(e) + (**self).encode(e) } } impl Decodable for path::PathBuf { + #[cfg(unix)] + fn decode(d: &mut D) -> Result { + use std::os::unix::prelude::*; + let bytes: Vec = try!(Decodable::decode(d)); + let s: OsString = OsStringExt::from_vec(bytes); + let mut p = path::PathBuf::new(); + p.push(s); + Ok(p) + } + #[cfg(windows)] fn decode(d: &mut D) -> Result { - let bytes: String = try!(Decodable::decode(d)); - Ok(path::PathBuf::from(bytes)) + use std::os::windows::prelude::*; + let bytes: Vec = try!(Decodable::decode(d)); + let s: OsString = OsStringExt::from_wide(&bytes); + let mut p = path::PathBuf::new(); + p.push(s); + Ok(p) } } @@ -597,8 +692,8 @@ impl Decodable for Arc { pub trait EncoderHelpers: Encoder { fn emit_from_vec(&mut self, v: &[T], f: F) - -> Result<(), Self::Error> - where F: FnMut(&mut Self, &T) -> Result<(), Self::Error>; + -> Result<(), ::Error> + where F: FnMut(&mut Self, &T) -> Result<(), ::Error>; } impl EncoderHelpers for S { @@ -618,8 +713,8 @@ impl EncoderHelpers for S { pub trait DecoderHelpers: Decoder { fn read_to_vec(&mut self, f: F) - -> Result, Self::Error> where - F: FnMut(&mut Self) -> Result; + -> Result, ::Error> where + F: FnMut(&mut Self) -> Result::Error>; } impl DecoderHelpers for D { diff --git a/src/external/term/.gitignore b/src/external/term/.gitignore new file mode 100644 index 0000000000000..4fffb2f89cbd8 --- /dev/null +++ b/src/external/term/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/src/external/term/.travis.yml b/src/external/term/.travis.yml new file mode 100644 index 0000000000000..3a2aef7a08409 --- /dev/null +++ b/src/external/term/.travis.yml @@ -0,0 +1,25 @@ +language: rust +rust: + - 1.0.0 + - beta + - nightly +sudo: false +script: + - cargo build --verbose + - cargo test --verbose + - cargo doc +after_success: | + [ $TRAVIS_BRANCH = master ] && + [ $TRAVIS_PULL_REQUEST = false ] && + [ $TRAVIS_RUST_VERSION = nightly ] && + echo '' > target/doc/index.html && + pip install ghp-import --user $USER && + $HOME/.local/bin/ghp-import -n target/doc && + git push -qf https://${TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages + +env: + global: + secure: Na+sfNSVDR8SdK5lFIbhvPj6zU+0NBTbHgugcCzhDEkvkaO0GLMYdhD3g+yAOR2DjIgn2Jdv1TGJkfD3KTPut52mmxftLkeA9528zqsiLD00JbPj8S71BcHIytOyGth84u+GdpNBZRvt5Fd3Pz1OgoEEeP/3O6uMe52+3Um/oPw= +notifications: + email: + on_success: never diff --git a/src/external/term/Cargo.toml b/src/external/term/Cargo.toml new file mode 100644 index 0000000000000..ef9f6a58bd778 --- /dev/null +++ b/src/external/term/Cargo.toml @@ -0,0 +1,21 @@ +[package] + +name = "term" +version = "0.2.7" +authors = ["The Rust Project Developers"] +license = "MIT/Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-lang/term" +homepage = "https://github.com/rust-lang/term" +documentation = "http://doc.rust-lang.org/term" +description = """ +A terminal formatting library +""" + +[target.i686-pc-windows-gnu.dependencies] +winapi = "0.1" +kernel32-sys = "0.1" + +[target.x86_64-pc-windows-gnu.dependencies] +winapi = "0.1" +kernel32-sys = "0.1" diff --git a/src/external/term/LICENSE-APACHE b/src/external/term/LICENSE-APACHE new file mode 100644 index 0000000000000..16fe87b06e802 --- /dev/null +++ b/src/external/term/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/external/term/LICENSE-MIT b/src/external/term/LICENSE-MIT new file mode 100644 index 0000000000000..39d4bdb5acd31 --- /dev/null +++ b/src/external/term/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/external/term/README.md b/src/external/term/README.md new file mode 100644 index 0000000000000..1453c197d5132 --- /dev/null +++ b/src/external/term/README.md @@ -0,0 +1,25 @@ +term +==== + +A Rust library for terminfo parsing and terminal colors. + +[![Build Status](https://travis-ci.org/rust-lang/term.svg?branch=master)](https://travis-ci.org/rust-lang/term) +[![Build status](https://ci.appveyor.com/api/projects/status/422c2ovagestqw89?svg=true)](https://ci.appveyor.com/project/alexcrichton/term) + +[Documentation](http://doc.rust-lang.org/term) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] + +term = "*" +``` + +and this to your crate root: + +```rust +extern crate term; +``` diff --git a/src/external/term/appveyor.yml b/src/external/term/appveyor.yml new file mode 100644 index 0000000000000..f74c851ad7100 --- /dev/null +++ b/src/external/term/appveyor.yml @@ -0,0 +1,11 @@ +install: + - ps: Start-FileDownload 'https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe' + - rust-nightly-i686-pc-windows-gnu.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --verbose diff --git a/src/external/term/src/lib.rs b/src/external/term/src/lib.rs new file mode 100644 index 0000000000000..ea4a10bcbaf96 --- /dev/null +++ b/src/external/term/src/lib.rs @@ -0,0 +1,247 @@ +// Copyright 2013-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. + +//! Terminal formatting library. +//! +//! This crate provides the `Terminal` trait, which abstracts over an [ANSI +//! Terminal][ansi] to provide color printing, among other things. There are two +//! implementations, the `TerminfoTerminal`, which uses control characters from +//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console +//! API][win]. +//! +//! # Usage +//! +//! This crate is [on crates.io](https://crates.io/crates/term) and can be +//! used by adding `term` to the dependencies in your project's `Cargo.toml`. +//! +//! ```toml +//! [dependencies] +//! +//! term = "0.2" +//! ``` +//! +//! and this to your crate root: +//! +//! ```rust +//! extern crate term; +//! ``` +//! +//! # Examples +//! +//! ```no_run +//! extern crate term; +//! use std::io::prelude::*; +//! +//! fn main() { +//! let mut t = term::stdout().unwrap(); +//! +//! t.fg(term::color::GREEN).unwrap(); +//! (write!(t, "hello, ")).unwrap(); +//! +//! t.fg(term::color::RED).unwrap(); +//! (writeln!(t, "world!")).unwrap(); +//! +//! assert!(t.reset().unwrap()); +//! } +//! ``` +//! +//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code +//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx +//! [ti]: https://en.wikipedia.org/wiki/Terminfo + +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/nightly/", + html_playground_url = "http://play.rust-lang.org/")] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] +#![cfg_attr(rust_build, feature(staged_api))] +#![cfg_attr(rust_build, staged_api)] +#![cfg_attr(rust_build, + unstable(feature = "rustc_private", + reason = "use the crates.io `term` library instead"))] + +use std::io::prelude::*; + +pub use terminfo::TerminfoTerminal; +#[cfg(windows)] +pub use win::WinConsole; + +use std::io::{self, Stdout, Stderr}; + +pub mod terminfo; + +#[cfg(windows)] +mod win; + +/// Alias for stdout terminals. +pub type StdoutTerminal = Terminal + Send; +/// Alias for stderr terminals. +pub type StderrTerminal = Terminal + Send; + +#[cfg(not(windows))] +/// Return a Terminal wrapping stdout, or None if a terminal couldn't be +/// opened. +pub fn stdout() -> Option> { + TerminfoTerminal::new(io::stdout()).map(|t| { + Box::new(t) as Box + }) +} + +#[cfg(windows)] +/// Return a Terminal wrapping stdout, or None if a terminal couldn't be +/// opened. +pub fn stdout() -> Option> { + TerminfoTerminal::new(io::stdout()).map(|t| { + Box::new(t) as Box + }).or_else(|| WinConsole::new(io::stdout()).ok().map(|t| { + Box::new(t) as Box + })) +} + +#[cfg(not(windows))] +/// Return a Terminal wrapping stderr, or None if a terminal couldn't be +/// opened. +pub fn stderr() -> Option> { + TerminfoTerminal::new(io::stderr()).map(|t| { + Box::new(t) as Box + }) +} + +#[cfg(windows)] +/// Return a Terminal wrapping stderr, or None if a terminal couldn't be +/// opened. +pub fn stderr() -> Option> { + TerminfoTerminal::new(io::stderr()).map(|t| { + Box::new(t) as Box + }).or_else(|| WinConsole::new(io::stderr()).ok().map(|t| { + Box::new(t) as Box + })) +} + + +/// Terminal color definitions +pub mod color { + /// Number for a terminal color + pub type Color = u16; + + pub const BLACK: Color = 0; + pub const RED: Color = 1; + pub const GREEN: Color = 2; + pub const YELLOW: Color = 3; + pub const BLUE: Color = 4; + pub const MAGENTA: Color = 5; + pub const CYAN: Color = 6; + pub const WHITE: Color = 7; + + pub const BRIGHT_BLACK: Color = 8; + pub const BRIGHT_RED: Color = 9; + pub const BRIGHT_GREEN: Color = 10; + pub const BRIGHT_YELLOW: Color = 11; + pub const BRIGHT_BLUE: Color = 12; + pub const BRIGHT_MAGENTA: Color = 13; + pub const BRIGHT_CYAN: Color = 14; + pub const BRIGHT_WHITE: Color = 15; +} + +/// Terminal attributes for use with term.attr(). +/// +/// Most attributes can only be turned on and must be turned off with term.reset(). +/// The ones that can be turned off explicitly take a boolean value. +/// Color is also represented as an attribute for convenience. +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum Attr { + /// Bold (or possibly bright) mode + Bold, + /// Dim mode, also called faint or half-bright. Often not supported + Dim, + /// Italics mode. Often not supported + Italic(bool), + /// Underline mode + Underline(bool), + /// Blink mode + Blink, + /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold + Standout(bool), + /// Reverse mode, inverts the foreground and background colors + Reverse, + /// Secure mode, also called invis mode. Hides the printed text + Secure, + /// Convenience attribute to set the foreground color + ForegroundColor(color::Color), + /// Convenience attribute to set the background color + BackgroundColor(color::Color) +} + +/// A terminal with similar capabilities to an ANSI Terminal +/// (foreground/background colors etc). +pub trait Terminal: Write { + /// The terminal's output writer type. + type Output: Write; + + /// Sets the foreground color to the given color. + /// + /// If the color is a bright color, but the terminal only supports 8 colors, + /// the corresponding normal color will be used instead. + /// + /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)` + /// if there was an I/O error. + fn fg(&mut self, color: color::Color) -> io::Result; + + /// Sets the background color to the given color. + /// + /// If the color is a bright color, but the terminal only supports 8 colors, + /// the corresponding normal color will be used instead. + /// + /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)` + /// if there was an I/O error. + fn bg(&mut self, color: color::Color) -> io::Result; + + /// Sets the given terminal attribute, if supported. Returns `Ok(true)` + /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if + /// there was an I/O error. + fn attr(&mut self, attr: Attr) -> io::Result; + + /// Returns whether the given terminal attribute is supported. + fn supports_attr(&self, attr: Attr) -> bool; + + /// Resets all terminal attributes and color to the default. + /// + /// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there + /// was an I/O error. + fn reset(&mut self) -> io::Result; + + /// Moves the cursor up one line. + /// + /// Returns `Ok(true)` if the cursor was moved, `Ok(false)` otherwise, and `Err(e)` + /// if there was an I/O error. + fn cursor_up(&mut self) -> io::Result; + + /// Deletes the text from the cursor location to the end of the line. + /// + /// Returns `Ok(true)` if the text was deleted, `Ok(false)` otherwise, and `Err(e)` + /// if there was an I/O error. + fn delete_line(&mut self) -> io::Result; + + /// Moves the cursor to the left edge of the current line. + /// + /// Returns `Ok(true)` if the text was deleted, `Ok(false)` otherwise, and `Err(e)` + /// if there was an I/O error. + fn carriage_return(&mut self) -> io::Result; + + /// Gets an immutable reference to the stream inside + fn get_ref<'a>(&'a self) -> &'a Self::Output; + + /// Gets a mutable reference to the stream inside + fn get_mut<'a>(&'a mut self) -> &'a mut Self::Output; + + /// Returns the contained stream, destroying the `Terminal` + fn into_inner(self) -> Self::Output where Self: Sized; +} diff --git a/src/external/term/src/terminfo/mod.rs b/src/external/term/src/terminfo/mod.rs new file mode 100644 index 0000000000000..36289fd32ee3d --- /dev/null +++ b/src/external/term/src/terminfo/mod.rs @@ -0,0 +1,275 @@ +// 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. + +//! Terminfo database interface. + +use std::collections::HashMap; +use std::env; +use std::error; +use std::fmt; +use std::fs::File; +use std::io::prelude::*; +use std::io; +use std::path::Path; + +use Attr; +use color; +use Terminal; +use self::searcher::get_dbpath_for_term; +use self::parser::compiled::{parse, msys_terminfo}; +use self::parm::{expand, Variables, Param}; + + +/// A parsed terminfo database entry. +#[derive(Debug)] +pub struct TermInfo { + /// Names for the terminal + pub names: Vec , + /// Map of capability name to boolean value + pub bools: HashMap, + /// Map of capability name to numeric value + pub numbers: HashMap, + /// Map of capability name to raw (unexpanded) string + pub strings: HashMap > +} + +/// A terminfo creation error. +#[derive(Debug)] +pub enum Error { + /// TermUnset Indicates that the environment doesn't include enough information to find + /// the terminfo entry. + TermUnset, + /// MalformedTerminfo indicates that parsing the terminfo entry failed. + MalformedTerminfo(String), + /// io::Error forwards any io::Errors encountered when finding or reading the terminfo entry. + IoError(io::Error), +} + +impl error::Error for Error { + fn description(&self) -> &str { "failed to create TermInfo" } + + fn cause(&self) -> Option<&error::Error> { + use self::Error::*; + match self { + &IoError(ref e) => Some(e), + _ => None, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Error::*; + match self { + &TermUnset => Ok(()), + &MalformedTerminfo(ref e) => e.fmt(f), + &IoError(ref e) => e.fmt(f), + } + } +} + +impl TermInfo { + /// Create a TermInfo based on current environment. + pub fn from_env() -> Result { + let term = match env::var("TERM") { + Ok(name) => TermInfo::from_name(&name), + Err(..) => return Err(Error::TermUnset), + }; + + if term.is_err() && env::var("MSYSCON").ok().map_or(false, |s| "mintty.exe" == s) { + // msys terminal + Ok(msys_terminfo()) + } else { + term + } + } + + /// Create a TermInfo for the named terminal. + pub fn from_name(name: &str) -> Result { + get_dbpath_for_term(name).ok_or_else(|| { + Error::IoError(io::Error::new(io::ErrorKind::NotFound, + "terminfo file not found")) + }).and_then(|p| { + TermInfo::from_path(&p) + }) + } + + /// Parse the given TermInfo. + pub fn from_path(path: &Path) -> Result { + File::open(path).map_err(|e| { + Error::IoError(e) + }).and_then(|ref mut file| { + parse(file, false).map_err(|e| { + Error::MalformedTerminfo(e) + }) + }) + } +} + +pub mod searcher; + +/// TermInfo format parsing. +pub mod parser { + //! ncurses-compatible compiled terminfo format parsing (term(5)) + pub mod compiled; +} +pub mod parm; + + +fn cap_for_attr(attr: Attr) -> &'static str { + match attr { + Attr::Bold => "bold", + Attr::Dim => "dim", + Attr::Italic(true) => "sitm", + Attr::Italic(false) => "ritm", + Attr::Underline(true) => "smul", + Attr::Underline(false) => "rmul", + Attr::Blink => "blink", + Attr::Standout(true) => "smso", + Attr::Standout(false) => "rmso", + Attr::Reverse => "rev", + Attr::Secure => "invis", + Attr::ForegroundColor(_) => "setaf", + Attr::BackgroundColor(_) => "setab" + } +} + +/// A Terminal that knows how many colors it supports, with a reference to its +/// parsed Terminfo database record. +pub struct TerminfoTerminal { + num_colors: u16, + out: T, + ti: TermInfo, +} + +impl Terminal for TerminfoTerminal { + type Output = T; + fn fg(&mut self, color: color::Color) -> io::Result { + let color = self.dim_if_necessary(color); + if self.num_colors > color { + return self.apply_cap("setaf", &[Param::Number(color as i16)]); + } + Ok(false) + } + + fn bg(&mut self, color: color::Color) -> io::Result { + let color = self.dim_if_necessary(color); + if self.num_colors > color { + return self.apply_cap("setab", &[Param::Number(color as i16)]); + } + Ok(false) + } + + fn attr(&mut self, attr: Attr) -> io::Result { + match attr { + Attr::ForegroundColor(c) => self.fg(c), + Attr::BackgroundColor(c) => self.bg(c), + _ => self.apply_cap(cap_for_attr(attr), &[]), + } + } + + fn supports_attr(&self, attr: Attr) -> bool { + match attr { + Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => { + self.num_colors > 0 + } + _ => { + let cap = cap_for_attr(attr); + self.ti.strings.get(cap).is_some() + } + } + } + + fn reset(&mut self) -> io::Result { + // are there any terminals that have color/attrs and not sgr0? + // Try falling back to sgr, then op + let cmd = match [ + "sg0", "sgr", "op" + ].iter().filter_map(|cap| { + self.ti.strings.get(*cap) + }).next() { + Some(op) => match expand(&op, &[], &mut Variables::new()) { + Ok(cmd) => cmd, + Err(_) => return Ok(false), + }, + None => return Ok(false), + }; + + self.out.write_all(&cmd).map(|_|true) + } + + fn cursor_up(&mut self) -> io::Result { + self.apply_cap("cuu1", &[]) + } + + fn delete_line(&mut self) -> io::Result { + self.apply_cap("dl", &[]) + } + + fn carriage_return(&mut self) -> io::Result { + self.apply_cap("cr", &[]) + } + + fn get_ref<'a>(&'a self) -> &'a T { &self.out } + + fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.out } + + fn into_inner(self) -> T where Self: Sized { self.out } +} + +impl TerminfoTerminal { + /// Create a new TerminfoTerminal with the given TermInfo and Write. + pub fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal { + let nc = if terminfo.strings.contains_key("setaf") + && terminfo.strings.contains_key("setab") { + terminfo.numbers.get("colors").map_or(0, |&n| n) + } else { 0 }; + + TerminfoTerminal { + out: out, + ti: terminfo, + num_colors: nc, + } + } + + /// Create a new TerminfoTerminal for the current environment with the given Write. + /// + /// Returns `None` when the terminfo cannot be found or parsed. + pub fn new(out: T) -> Option> { + TermInfo::from_env().map(move |ti| TerminfoTerminal::new_with_terminfo(out, ti)).ok() + } + + fn dim_if_necessary(&self, color: color::Color) -> color::Color { + if color >= self.num_colors && color >= 8 && color < 16 { + color-8 + } else { color } + } + + fn apply_cap(&mut self, cmd: &str, params: &[Param]) -> io::Result { + if let Some(cmd) = self.ti.strings.get(cmd) { + if let Ok(s) = expand(&cmd, params, &mut Variables::new()) { + try!(self.out.write_all(&s)); + return Ok(true) + } + } + Ok(false) + } +} + + +impl Write for TerminfoTerminal { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.out.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.out.flush() + } +} diff --git a/src/libterm/terminfo/parm.rs b/src/external/term/src/terminfo/parm.rs similarity index 90% rename from src/libterm/terminfo/parm.rs rename to src/external/term/src/terminfo/parm.rs index 2b8c24741ae7c..17061113397fc 100644 --- a/src/libterm/terminfo/parm.rs +++ b/src/external/term/src/terminfo/parm.rs @@ -10,15 +10,16 @@ //! Parameterized string expansion -pub use self::Param::*; +use self::Param::*; use self::States::*; use self::FormatState::*; use self::FormatOp::*; -use std::ascii::OwnedAsciiExt; -use std::mem::replace; + +use std::ascii::AsciiExt; use std::iter::repeat; +use std::mem::replace; -#[derive(Copy, Clone, PartialEq)] +#[derive(Clone, Copy, PartialEq)] enum States { Nothing, Percent, @@ -27,15 +28,15 @@ enum States { PushParam, CharConstant, CharClose, - IntConstant(isize), + IntConstant(i16), FormatPattern(Flags, FormatState), - SeekIfElse(isize), - SeekIfElsePercent(isize), - SeekIfEnd(isize), - SeekIfEndPercent(isize) + SeekIfElse(usize), + SeekIfElsePercent(usize), + SeekIfEnd(usize), + SeekIfEndPercent(usize) } -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, PartialEq, Clone)] enum FormatState { FormatStateFlags, FormatStateWidth, @@ -47,7 +48,7 @@ enum FormatState { #[derive(Clone)] pub enum Param { Words(String), - Number(isize) + Number(i16) } /// Container for static and dynamic variable arrays @@ -109,7 +110,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) *dst = (*src).clone(); } - for &c in cap { + for &c in cap.iter() { let cur = c as char; let mut old_state = state; match state { @@ -123,12 +124,12 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) Percent => { match cur { '%' => { output.push(c); state = Nothing }, - 'c' => if !stack.is_empty() { + 'c' => if stack.len() > 0 { match stack.pop().unwrap() { // if c is 0, use 0200 (128) for ncurses compatibility Number(c) => { output.push(if c == 0 { - 128 + 128u8 } else { c as u8 }) @@ -141,9 +142,9 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) 'g' => state = GetVar, '\'' => state = CharConstant, '{' => state = IntConstant(0), - 'l' => if !stack.is_empty() { + 'l' => if stack.len() > 0 { match stack.pop().unwrap() { - Words(s) => stack.push(Number(s.len() as isize)), + Words(s) => stack.push(Number(s.len() as i16)), _ => return Err("a non-str was used with %l".to_string()) } } else { return Err("stack is empty".to_string()) }, @@ -231,14 +232,14 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) _ => return Err("non-numbers on stack with logical or".to_string()) } } else { return Err("stack is empty".to_string()) }, - '!' => if !stack.is_empty() { + '!' => if stack.len() > 0 { match stack.pop().unwrap() { Number(0) => stack.push(Number(1)), Number(_) => stack.push(Number(0)), _ => return Err("non-number on stack with logical not".to_string()) } } else { return Err("stack is empty".to_string()) }, - '~' => if !stack.is_empty() { + '~' => if stack.len() > 0 { match stack.pop().unwrap() { Number(x) => stack.push(Number(!x)), _ => return Err("non-number on stack with %~".to_string()) @@ -253,11 +254,11 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) }, // printf-style support for %doxXs - 'd'|'o'|'x'|'X'|'s' => if !stack.is_empty() { + 'd'|'o'|'x'|'X'|'s' => if stack.len() > 0 { let flags = Flags::new(); let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), flags); if res.is_err() { return res } - output.push_all(&res.unwrap()) + output.extend(res.unwrap().iter().map(|x| *x)) } else { return Err("stack is empty".to_string()) }, ':'|'#'|' '|'.'|'0'...'9' => { let mut flags = Flags::new(); @@ -278,7 +279,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) // conditionals '?' => (), - 't' => if !stack.is_empty() { + 't' => if stack.len() > 0 { match stack.pop().unwrap() { Number(0) => state = SeekIfElse(0), Number(_) => (), @@ -290,7 +291,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) ';' => (), _ => { - return Err(format!("unrecognized format option {:?}", cur)) + return Err(format!("unrecognized format option {}", cur)) } } }, @@ -303,12 +304,12 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) }, SetVar => { if cur >= 'A' && cur <= 'Z' { - if !stack.is_empty() { + if stack.len() > 0 { let idx = (cur as u8) - b'A'; vars.sta[idx as usize] = stack.pop().unwrap(); } else { return Err("stack is empty".to_string()) } } else if cur >= 'a' && cur <= 'z' { - if !stack.is_empty() { + if stack.len() > 0 { let idx = (cur as u8) - b'a'; vars.dyn[idx as usize] = stack.pop().unwrap(); } else { return Err("stack is empty".to_string()) } @@ -328,7 +329,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) } }, CharConstant => { - stack.push(Number(c as isize)); + stack.push(Number(c as i16)); state = CharClose; }, CharClose => { @@ -337,25 +338,28 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) } }, IntConstant(i) => { - match cur { - '}' => { - stack.push(Number(i)); - state = Nothing; - } - '0'...'9' => { - state = IntConstant(i*10 + (cur as isize - '0' as isize)); - old_state = Nothing; + if cur == '}' { + stack.push(Number(i)); + state = Nothing; + } else if let Some(digit) = cur.to_digit(10) { + match i.checked_mul(10).and_then(|i_ten|i_ten.checked_add(digit as i16)) { + Some(i) => { + state = IntConstant(i); + old_state = Nothing; + } + None => return Err("int constant too large".to_string()) } - _ => return Err("bad isize constant".to_string()) + } else { + return Err("bad int constant".to_string()); } } FormatPattern(ref mut flags, ref mut fstate) => { old_state = Nothing; match (*fstate, cur) { - (_,'d')|(_,'o')|(_,'x')|(_,'X')|(_,'s') => if !stack.is_empty() { + (_,'d')|(_,'o')|(_,'x')|(_,'X')|(_,'s') => if stack.len() > 0 { let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), *flags); if res.is_err() { return res } - output.push_all(&res.unwrap()); + output.extend(res.unwrap().iter().map(|x| *x)); // will cause state to go to Nothing old_state = FormatPattern(*flags, *fstate); } else { return Err("stack is empty".to_string()) }, @@ -444,7 +448,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) Ok(output) } -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, PartialEq, Clone)] struct Flags { width: usize, precision: usize, @@ -496,16 +500,15 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result ,String> { let mut s = match val { Number(d) => { let s = match (op, flags.sign) { - (FormatDigit, true) => format!("{:+}", d).into_bytes(), - (FormatDigit, false) => format!("{}", d).into_bytes(), - (FormatOctal, _) => format!("{:o}", d).into_bytes(), - (FormatHex, _) => format!("{:x}", d).into_bytes(), - (FormatHEX, _) => format!("{:X}", d).into_bytes(), - (FormatString, _) => { - return Err("non-number on stack with %s".to_string()) - } + (FormatDigit, true) => format!("{:+}", d), + (FormatDigit, false) => format!("{}", d), + (FormatOctal, _) => format!("{:o}", d), + (FormatHex, _) => format!("{:x}", d), + (FormatHEX, _) => format!("{:X}", d), + (FormatString, _) => return Err("non-number on stack with %s".to_string()) }; - let mut s: Vec = s.into_iter().collect(); + + let mut s: Vec = s.into_bytes().into_iter().collect(); if flags.precision > s.len() { let mut s_ = Vec::with_capacity(flags.precision); let n = flags.precision - s.len(); @@ -532,7 +535,7 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result ,String> { } } FormatHEX => { - s = s.into_ascii_uppercase(); + s = s.to_ascii_uppercase(); if flags.alternate { let s_ = replace(&mut s, vec!(b'0', b'X')); s.extend(s_.into_iter()); @@ -552,7 +555,7 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result ,String> { s } _ => { - return Err(format!("non-string on stack with %{:?}", + return Err(format!("non-string on stack with %{}", op.to_char())) } } @@ -573,8 +576,9 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result ,String> { } #[cfg(test)] -mod tests { - use super::{expand,Param,Words,Variables,Number}; +mod test { + use super::{expand, Variables}; + use super::Param::{self, Words, Number}; use std::result::Result::Ok; #[test] @@ -608,12 +612,12 @@ mod tests { Result, String> { let mut u8v: Vec<_> = fmt.bytes().collect(); - u8v.extend(cap.bytes()); + u8v.extend(cap.as_bytes().iter().map(|&b| b)); expand(&u8v, params, vars) } let caps = ["%d", "%c", "%s", "%Pa", "%l", "%!", "%~"]; - for &cap in &caps { + for &cap in caps.iter() { let res = get_res("", cap, &[], vars); assert!(res.is_err(), "Op {} succeeded incorrectly with 0 stack entries", cap); @@ -627,7 +631,7 @@ mod tests { "Op {} failed with 1 stack entry: {}", cap, res.err().unwrap()); } let caps = ["%+", "%-", "%*", "%/", "%m", "%&", "%|", "%A", "%O"]; - for &cap in &caps { + for &cap in caps.iter() { let res = expand(cap.as_bytes(), &[], vars); assert!(res.is_err(), "Binop {} succeeded incorrectly with 0 stack entries", cap); @@ -636,7 +640,7 @@ mod tests { "Binop {} succeeded incorrectly with 1 stack entry", cap); let res = get_res("%{1}%{2}", cap, &[], vars); assert!(res.is_ok(), - "Binop {} failed with 2 stack entries: {:?}", cap, res.err().unwrap()); + "Binop {} failed with 2 stack entries: {}", cap, res.err().unwrap()); } } @@ -647,20 +651,20 @@ mod tests { #[test] fn test_comparison_ops() { - let v = [('<', [1, 0, 0]), ('=', [0, 1, 0]), ('>', [0, 0, 1])]; - for &(op, bs) in &v { + let v = [('<', [1u8, 0u8, 0u8]), ('=', [0u8, 1u8, 0u8]), ('>', [0u8, 0u8, 1u8])]; + for &(op, bs) in v.iter() { let s = format!("%{{1}}%{{2}}%{}%d", op); let res = expand(s.as_bytes(), &[], &mut Variables::new()); assert!(res.is_ok(), res.err().unwrap()); - assert_eq!(res.unwrap(), [b'0' + bs[0]]); + assert_eq!(res.unwrap(), vec!(b'0' + bs[0])); let s = format!("%{{1}}%{{1}}%{}%d", op); let res = expand(s.as_bytes(), &[], &mut Variables::new()); assert!(res.is_ok(), res.err().unwrap()); - assert_eq!(res.unwrap(), [b'0' + bs[1]]); + assert_eq!(res.unwrap(), vec!(b'0' + bs[1])); let s = format!("%{{2}}%{{1}}%{}%d", op); let res = expand(s.as_bytes(), &[], &mut Variables::new()); assert!(res.is_ok(), res.err().unwrap()); - assert_eq!(res.unwrap(), [b'0' + bs[2]]); + assert_eq!(res.unwrap(), vec!(b'0' + bs[2])); } } diff --git a/src/libterm/terminfo/parser/compiled.rs b/src/external/term/src/terminfo/parser/compiled.rs similarity index 79% rename from src/libterm/terminfo/parser/compiled.rs rename to src/external/term/src/terminfo/parser/compiled.rs index ef42d8c2506b3..2cf4a4ecb1897 100644 --- a/src/libterm/terminfo/parser/compiled.rs +++ b/src/external/term/src/terminfo/parser/compiled.rs @@ -158,62 +158,89 @@ pub static stringnames: &'static[&'static str] = &[ "cbt", "_", "cr", "csr", "tb "OTG3", "OTG1", "OTG4", "OTGR", "OTGL", "OTGU", "OTGD", "OTGH", "OTGV", "OTGC", "meml", "memu", "box1"]; -/// Parse a compiled terminfo entry, using long capability names if `longnames` is true -pub fn parse(file: &mut Read, longnames: bool) - -> Result, String> { - macro_rules! try { ($e:expr) => ( +fn read_le_u16(r: &mut io::Read) -> io::Result { + let mut b = [0; 2]; + let mut amt = 0; + while amt < b.len() { + match try!(r.read(&mut b[amt..])) { + 0 => return Err(io::Error::new(io::ErrorKind::Other, "end of file")), + n => amt += n, + } + } + Ok((b[0] as u16) | ((b[1] as u16) << 8)) +} + +fn read_byte(r: &mut io::Read) -> io::Result { + match r.bytes().next() { + Some(s) => s, + None => Err(io::Error::new(io::ErrorKind::Other, "end of file")) + } +} + +/// Parse a compiled terminfo entry, using long capability names if `longnames` +/// is true +pub fn parse(file: &mut io::Read, longnames: bool) -> Result { + macro_rules! try( ($e:expr) => ( match $e { Ok(e) => e, - Err(e) => return Err(format!("{:?}", e)) + Err(e) => return Err(format!("{}", e)) } - ) } - - let bnames; - let snames; - let nnames; + ) ); - if longnames { - bnames = boolfnames; - snames = stringfnames; - nnames = numfnames; + let (bnames, snames, nnames) = if longnames { + (boolfnames, stringfnames, numfnames) } else { - bnames = boolnames; - snames = stringnames; - nnames = numnames; - } + (boolnames, stringnames, numnames) + }; // Check magic number let magic = try!(read_le_u16(file)); if magic != 0x011A { return Err(format!("invalid magic number: expected {:x}, found {:x}", - 0x011A_usize, magic as usize)); + 0x011A, magic)); } - let names_bytes = try!(read_le_u16(file)) as isize; - let bools_bytes = try!(read_le_u16(file)) as isize; - let numbers_count = try!(read_le_u16(file)) as isize; - let string_offsets_count = try!(read_le_u16(file)) as isize; - let string_table_bytes = try!(read_le_u16(file)) as isize; + // According to the spec, these fields must be >= -1 where -1 means that the feature is not + // supported. Using 0 instead of -1 works because we skip sections with length 0. + macro_rules! read_nonneg { + () => {{ + match try!(read_le_u16(file)) as i16 { + n if n >= 0 => n as usize, + -1 => 0, + _ => return Err("incompatible file: length fields must be >= -1".to_string()), + } + }} + } + + let names_bytes = read_nonneg!(); + let bools_bytes = read_nonneg!(); + let numbers_count = read_nonneg!(); + let string_offsets_count = read_nonneg!(); + let string_table_bytes = read_nonneg!(); - assert!(names_bytes > 0); + if names_bytes == 0 { + return Err("incompatible file: names field must be \ + at least 1 byte wide".to_string()); + } - if (bools_bytes as usize) > boolnames.len() { + if bools_bytes > boolnames.len() { return Err("incompatible file: more booleans than \ expected".to_string()); } - if (numbers_count as usize) > numnames.len() { + if numbers_count > numnames.len() { return Err("incompatible file: more numbers than \ expected".to_string()); } - if (string_offsets_count as usize) > stringnames.len() { + if string_offsets_count > stringnames.len() { return Err("incompatible file: more string offsets than \ expected".to_string()); } // don't read NUL - let bytes = try!(read_exact(file, names_bytes as usize - 1)); + let mut bytes = Vec::new(); + try!(file.take((names_bytes - 1) as u64).read_to_end(&mut bytes)); let names_str = match String::from_utf8(bytes) { Ok(s) => s, Err(_) => return Err("input not utf-8".to_string()), @@ -222,53 +249,43 @@ pub fn parse(file: &mut Read, longnames: bool) let term_names: Vec = names_str.split('|') .map(|s| s.to_string()) .collect(); - - try!(read_byte(file)); // consume NUL - - let mut bools_map = HashMap::new(); - if bools_bytes != 0 { - for i in 0..bools_bytes { - let b = try!(read_byte(file)); - if b == 1 { - bools_map.insert(bnames[i as usize].to_string(), true); - } - } + // consume NUL + if try!(read_byte(file)) != b'\0' { + return Err("incompatible file: missing null terminator \ + for names section".to_string()); } + let bools_map: HashMap = try!( + (0..bools_bytes).filter_map(|i| match read_byte(file) { + Err(e) => Some(Err(e)), + Ok(1) => Some(Ok((bnames[i].to_string(), true))), + Ok(_) => None + }).collect()); + if (bools_bytes + names_bytes) % 2 == 1 { try!(read_byte(file)); // compensate for padding } - let mut numbers_map = HashMap::new(); - if numbers_count != 0 { - for i in 0..numbers_count { - let n = try!(read_le_u16(file)); - if n != 0xFFFF { - numbers_map.insert(nnames[i as usize].to_string(), n); - } - } - } + let numbers_map: HashMap = try!( + (0..numbers_count).filter_map(|i| match read_le_u16(file) { + Ok(0xFFFF) => None, + Ok(n) => Some(Ok((nnames[i].to_string(), n))), + Err(e) => Some(Err(e)) + }).collect()); - let mut string_map = HashMap::new(); + let string_map: HashMap> = if string_offsets_count > 0 { + let string_offsets: Vec = try!((0..string_offsets_count).map(|_| { + read_le_u16(file) + }).collect()); - if string_offsets_count != 0 { - let mut string_offsets = Vec::with_capacity(10); - for _ in 0..string_offsets_count { - string_offsets.push(try!(read_le_u16(file))); - } + let mut string_table = Vec::new(); + try!(file.take(string_table_bytes as u64).read_to_end(&mut string_table)); - let string_table = try!(read_exact(file, string_table_bytes as usize)); - - if string_table.len() != string_table_bytes as usize { - return Err("error: hit EOF before end of string \ - table".to_string()); - } - - for (i, v) in string_offsets.iter().enumerate() { - let offset = *v; - if offset == 0xFFFF { // non-entry - continue; - } + try!(string_offsets.into_iter().enumerate().filter(|&(_, offset)| { + // non-entry + offset != 0xFFFF + }).map(|(i, offset)| { + let offset = offset as usize; let name = if snames[i] == "_" { stringfnames[i] @@ -279,30 +296,22 @@ pub fn parse(file: &mut Read, longnames: bool) if offset == 0xFFFE { // undocumented: FFFE indicates cap@, which means the capability is not present // unsure if the handling for this is correct - string_map.insert(name.to_string(), Vec::new()); - continue; + return Ok((name.to_string(), Vec::new())); } - // Find the offset of the NUL we want to go to - let nulpos = string_table[offset as usize .. string_table_bytes as usize] - .iter().position(|&b| b == 0); + let nulpos = string_table[offset..string_table_bytes].iter().position(|&b| b == 0); match nulpos { - Some(len) => { - string_map.insert(name.to_string(), - string_table[offset as usize .. - (offset as usize + len)].to_vec()) - }, - None => { - return Err("invalid file: missing NUL in \ - string_table".to_string()); - } - }; - } - } + Some(len) => Ok((name.to_string(), string_table[offset..offset + len].to_vec())), + None => Err("invalid file: missing NUL in string_table".to_string()), + } + }).collect()) + } else { + HashMap::new() + }; // And that's all there is to it - Ok(box TermInfo { + Ok(TermInfo { names: term_names, bools: bools_map, numbers: numbers_map, @@ -310,42 +319,27 @@ pub fn parse(file: &mut Read, longnames: bool) }) } -fn read_le_u16(r: &mut R) -> io::Result { - let mut b = [0; 2]; - assert_eq!(try!(r.read(&mut b)), 2); - Ok((b[0] as u16) | ((b[1] as u16) << 8)) -} - -fn read_byte(r: &mut R) -> io::Result { - let mut b = [0; 1]; - assert_eq!(try!(r.read(&mut b)), 1); - Ok(b[0]) -} - -fn read_exact(r: &mut R, sz: usize) -> io::Result> { - let mut v = Vec::with_capacity(sz); - try!(r.take(sz as u64).read_to_end(&mut v)); - assert_eq!(v.len(), sz); - Ok(v) -} - /// Create a dummy TermInfo struct for msys terminals -pub fn msys_terminfo() -> Box { +pub fn msys_terminfo() -> TermInfo { let mut strings = HashMap::new(); strings.insert("sgr0".to_string(), b"\x1B[0m".to_vec()); strings.insert("bold".to_string(), b"\x1B[1m".to_vec()); strings.insert("setaf".to_string(), b"\x1B[3%p1%dm".to_vec()); strings.insert("setab".to_string(), b"\x1B[4%p1%dm".to_vec()); - box TermInfo { + + let mut numbers = HashMap::new(); + numbers.insert("colors".to_string(), 8u16); + + TermInfo { names: vec!("cygwin".to_string()), // msys is a fork of an older cygwin version bools: HashMap::new(), - numbers: HashMap::new(), + numbers: numbers, strings: strings } } #[cfg(test)] -mod tests { +mod test { use super::{boolnames, boolfnames, numnames, numfnames, stringnames, stringfnames}; @@ -355,4 +349,11 @@ mod tests { assert_eq!(numfnames.len(), numnames.len()); assert_eq!(stringfnames.len(), stringnames.len()); } + + #[test] + #[ignore(reason = "no ncurses on buildbots, needs a bundled terminfo file to test against")] + fn test_parse() { + // FIXME #6870: Distribute a compiled file in src/tests and test there + // parse(io::fs_reader(&p("/usr/share/terminfo/r/rxvt-256color")).unwrap(), false); + } } diff --git a/src/external/term/src/terminfo/searcher.rs b/src/external/term/src/terminfo/searcher.rs new file mode 100644 index 0000000000000..207d5e0b281c7 --- /dev/null +++ b/src/external/term/src/terminfo/searcher.rs @@ -0,0 +1,79 @@ +// 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. + +//! ncurses-compatible database discovery +//! +//! Does not support hashed database, only filesystem! + +use std::env; +use std::fs; +use std::path::PathBuf; + +/// Return path to database entry for `term` +pub fn get_dbpath_for_term(term: &str) -> Option { + if term.len() == 0 { + return None; + } + + let mut dirs_to_search = Vec::new(); + let first_char = term.chars().next().unwrap(); + + // Find search directory + match env::var_os("TERMINFO") { + Some(dir) => dirs_to_search.push(PathBuf::from(dir)), + None => { + if let Some(mut homedir) = env::home_dir() { + // ncurses compatibility; + homedir.push(".terminfo"); + dirs_to_search.push(homedir) + } + match env::var("TERMINFO_DIRS") { + Ok(dirs) => for i in dirs.split(':') { + if i == "" { + dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); + } else { + dirs_to_search.push(PathBuf::from(i)); + } + }, + // Found nothing in TERMINFO_DIRS, use the default paths: + // According to /etc/terminfo/README, after looking at + // ~/.terminfo, ncurses will search /etc/terminfo, then + // /lib/terminfo, and eventually /usr/share/terminfo. + Err(..) => { + dirs_to_search.push(PathBuf::from("/etc/terminfo")); + dirs_to_search.push(PathBuf::from("/lib/terminfo")); + dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); + } + } + } + }; + + // Look for the terminal in all of the search directories + for mut p in dirs_to_search { + if fs::metadata(&p).is_ok() { + p.push(&first_char.to_string()); + p.push(&term); + if fs::metadata(&p).is_ok() { + return Some(p); + } + p.pop(); + p.pop(); + + // on some installations the dir is named after the hex of the char + // (e.g. OS X) + p.push(&format!("{:x}", first_char as usize)); + p.push(term); + if fs::metadata(&p).is_ok() { + return Some(p); + } + } + } + None +} diff --git a/src/external/term/src/win.rs b/src/external/term/src/win.rs new file mode 100644 index 0000000000000..694d794ad4227 --- /dev/null +++ b/src/external/term/src/win.rs @@ -0,0 +1,274 @@ +// Copyright 2013-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. + +//! Windows console handling + +// FIXME (#13400): this is only a tiny fraction of the Windows console api + +extern crate kernel32; +extern crate winapi; + +use std::ffi::OsStr; +use std::io::prelude::*; +use std::io; +use std::os::windows::ffi::OsStrExt; +use std::ptr; + +use Attr; +use color; +use Terminal; + +/// A Terminal implementation which uses the Win32 Console API. +pub struct WinConsole { + buf: T, + def_foreground: color::Color, + def_background: color::Color, + foreground: color::Color, + background: color::Color, +} + +fn color_to_bits(color: color::Color) -> u16 { + // magic numbers from mingw-w64's wincon.h + + let bits = match color % 8 { + color::BLACK => 0, + color::BLUE => 0x1, + color::GREEN => 0x2, + color::RED => 0x4, + color::YELLOW => 0x2 | 0x4, + color::MAGENTA => 0x1 | 0x4, + color::CYAN => 0x1 | 0x2, + color::WHITE => 0x1 | 0x2 | 0x4, + _ => unreachable!() + }; + + if color >= 8 { + bits | 0x8 + } else { + bits + } +} + +fn bits_to_color(bits: u16) -> color::Color { + let color = match bits & 0x7 { + 0 => color::BLACK, + 0x1 => color::BLUE, + 0x2 => color::GREEN, + 0x4 => color::RED, + 0x6 => color::YELLOW, + 0x5 => color::MAGENTA, + 0x3 => color::CYAN, + 0x7 => color::WHITE, + _ => unreachable!() + }; + + color | (bits & 0x8) // copy the hi-intensity bit +} + +// Just get a handle to the current console buffer whatever it is +fn conout() -> io::Result { + let name: &OsStr = "CONOUT$\0".as_ref(); + let name: Vec = name.encode_wide().collect(); + let handle = unsafe { + kernel32::CreateFileW( + name.as_ptr(), + winapi::GENERIC_READ | winapi::GENERIC_WRITE, + winapi::FILE_SHARE_WRITE, + ptr::null_mut(), + winapi::OPEN_EXISTING, + 0, + ptr::null_mut(), + ) + }; + if handle == winapi::INVALID_HANDLE_VALUE { + Err(io::Error::last_os_error()) + } else { + Ok(handle) + } +} + +// This test will only pass if it is running in an actual console, probably +#[test] +fn test_conout() { + assert!(conout().is_ok()) +} + +impl WinConsole { + fn apply(&mut self) -> io::Result<()> { + let out = try!(conout()); + let _unused = self.buf.flush(); + let mut accum: winapi::WORD = 0; + accum |= color_to_bits(self.foreground); + accum |= color_to_bits(self.background) << 4; + unsafe { + kernel32::SetConsoleTextAttribute(out, accum); + } + Ok(()) + } + + /// Returns `None` whenever the terminal cannot be created for some + /// reason. + pub fn new(out: T) -> io::Result> { + let fg; + let bg; + let handle = try!(conout()); + unsafe { + let mut buffer_info = ::std::mem::uninitialized(); + if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) != 0 { + fg = bits_to_color(buffer_info.wAttributes); + bg = bits_to_color(buffer_info.wAttributes >> 4); + } else { + return Err(io::Error::last_os_error()) + } + } + Ok(WinConsole { + buf: out, + def_foreground: fg, + def_background: bg, + foreground: fg, + background: bg, + }) + } +} + +impl Write for WinConsole { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.buf.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.buf.flush() + } +} + +impl Terminal for WinConsole { + type Output = T; + + fn fg(&mut self, color: color::Color) -> io::Result { + self.foreground = color; + try!(self.apply()); + + Ok(true) + } + + fn bg(&mut self, color: color::Color) -> io::Result { + self.background = color; + try!(self.apply()); + + Ok(true) + } + + fn attr(&mut self, attr: Attr) -> io::Result { + match attr { + Attr::ForegroundColor(f) => { + self.foreground = f; + try!(self.apply()); + Ok(true) + }, + Attr::BackgroundColor(b) => { + self.background = b; + try!(self.apply()); + Ok(true) + }, + _ => Ok(false) + } + } + + fn supports_attr(&self, attr: Attr) -> bool { + // it claims support for underscore and reverse video, but I can't get + // it to do anything -cmr + match attr { + Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => true, + _ => false + } + } + + fn reset(&mut self) -> io::Result { + self.foreground = self.def_foreground; + self.background = self.def_background; + try!(self.apply()); + + Ok(true) + } + + fn cursor_up(&mut self) -> io::Result { + let _unused = self.buf.flush(); + let handle = try!(conout()); + unsafe { + let mut buffer_info = ::std::mem::uninitialized(); + if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) != 0 { + let (x, y) = (buffer_info.dwCursorPosition.X, buffer_info.dwCursorPosition.Y); + if y == 0 { + Ok(false) + } else { + let pos = winapi::COORD { X: x, Y: y - 1 }; + if kernel32::SetConsoleCursorPosition(handle, pos) != 0 { + Ok(true) + } else { + Err(io::Error::last_os_error()) + } + } + } else { + Err(io::Error::last_os_error()) + } + } + } + + fn delete_line(&mut self) -> io::Result { + let _unused = self.buf.flush(); + let handle = try!(conout()); + unsafe { + let mut buffer_info = ::std::mem::uninitialized(); + if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) == 0 { + return Err(io::Error::last_os_error()) + } + let pos = buffer_info.dwCursorPosition; + let size = buffer_info.dwSize; + let num = (size.X - pos.X) as winapi::DWORD; + let mut written = 0; + if kernel32::FillConsoleOutputCharacterW(handle, 0, num, pos, &mut written) == 0 { + return Err(io::Error::last_os_error()) + } + if kernel32::FillConsoleOutputAttribute(handle, 0, num, pos, &mut written) == 0 { + return Err(io::Error::last_os_error()) + } + Ok(written != 0) + } + } + + fn carriage_return(&mut self) -> io::Result { + let _unused = self.buf.flush(); + let handle = try!(conout()); + unsafe { + let mut buffer_info = ::std::mem::uninitialized(); + if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) != 0 { + let (x, y) = (buffer_info.dwCursorPosition.X, buffer_info.dwCursorPosition.Y); + if x == 0 { + Ok(false) + } else { + let pos = winapi::COORD { X: 0, Y: y }; + if kernel32::SetConsoleCursorPosition(handle, pos) != 0 { + Ok(true) + } else { + Err(io::Error::last_os_error()) + } + } + } else { + Err(io::Error::last_os_error()) + } + } + } + + fn get_ref<'a>(&'a self) -> &'a T { &self.buf } + + fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf } + + fn into_inner(self) -> T where Self: Sized { self.buf } +} diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 41ae0f2d5e203..33ab2cedc01e9 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -129,7 +129,7 @@ #![cfg_attr(test, feature(test))] -extern crate serialize; +extern crate rustc_serialize as serialize; #[macro_use] extern crate log; #[cfg(test)] extern crate test; @@ -641,7 +641,7 @@ pub mod reader { fn read_u32(&mut self) -> DecodeResult { Ok(try!(self._next_int(EsU8, EsU32)) as u32) } fn read_u16(&mut self) -> DecodeResult { Ok(try!(self._next_int(EsU8, EsU16)) as u16) } fn read_u8(&mut self) -> DecodeResult { Ok(doc_as_u8(try!(self.next_doc(EsU8)))) } - fn read_uint(&mut self) -> DecodeResult { + fn read_usize(&mut self) -> DecodeResult { let v = try!(self._next_int(EsU8, EsU64)); if v > (::std::usize::MAX as u64) { Err(IntTooBig(v as usize)) @@ -654,7 +654,7 @@ pub mod reader { fn read_i32(&mut self) -> DecodeResult { Ok(try!(self._next_int(EsI8, EsI32)) as i32) } fn read_i16(&mut self) -> DecodeResult { Ok(try!(self._next_int(EsI8, 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 { + fn read_isize(&mut self) -> DecodeResult { let v = try!(self._next_int(EsI8, EsI64)) as i64; if v > (isize::MAX as i64) || v < (isize::MIN as i64) { debug!("FIXME \\#6122: Removing this makes this function miscompile"); @@ -1125,7 +1125,7 @@ pub mod writer { Ok(()) } - fn emit_uint(&mut self, v: usize) -> EncodeResult { + fn emit_usize(&mut self, v: usize) -> EncodeResult { self.emit_u64(v as u64) } fn emit_u64(&mut self, v: u64) -> EncodeResult { @@ -1153,7 +1153,7 @@ pub mod writer { self.wr_tagged_raw_u8(EsU8 as usize, v) } - fn emit_int(&mut self, v: isize) -> EncodeResult { + fn emit_isize(&mut self, v: isize) -> EncodeResult { self.emit_i64(v as i64) } fn emit_i64(&mut self, v: i64) -> EncodeResult { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 4a715ca621cc2..0eac502fd1c8c 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -58,15 +58,13 @@ extern crate libc; extern crate rustc_llvm; extern crate rustc_back; extern crate rustc_data_structures; -extern crate serialize; +extern crate rustc_serialize; extern crate rbml; extern crate collections; #[macro_use] extern crate log; #[macro_use] extern crate syntax; #[macro_use] #[no_link] extern crate rustc_bitflags; -extern crate serialize as rustc_serialize; // used by deriving - #[cfg(test)] extern crate test; diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index be285d975b81d..b7fe911f8f547 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -43,7 +43,7 @@ use std::str; use rbml::reader; use rbml; -use serialize::Decodable; +use rustc_serialize::Decodable; use syntax::ast_map; use syntax::attr; use syntax::parse::token::{IdentInterner, special_idents}; diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 8eefb4d5011d2..d35abdeff1fbb 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -27,7 +27,7 @@ use middle::ty::{self, Ty}; use middle::stability; use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; -use serialize::Encodable; +use rustc_serialize::Encodable; use std::cell::RefCell; use std::hash::{Hash, Hasher, SipHasher}; use std::io::prelude::*; diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index fda57c9dc610a..262ef8a064322 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -47,9 +47,9 @@ use std::fmt::Debug; use rbml::reader; use rbml::writer::Encoder; use rbml; -use serialize; -use serialize::{Decodable, Decoder, DecoderHelpers, Encodable}; -use serialize::EncoderHelpers; +use rustc_serialize; +use rustc_serialize::{Decodable, Decoder, DecoderHelpers, Encodable}; +use rustc_serialize::EncoderHelpers; #[cfg(test)] use std::io::Cursor; #[cfg(test)] use syntax::parse; @@ -313,8 +313,8 @@ trait def_id_encoder_helpers { fn emit_def_id(&mut self, did: ast::DefId); } -impl def_id_encoder_helpers for S - where ::Error: Debug +impl def_id_encoder_helpers for S + where ::Error: Debug { fn emit_def_id(&mut self, did: ast::DefId) { did.encode(self).unwrap() @@ -327,8 +327,8 @@ trait def_id_decoder_helpers { cdata: &cstore::crate_metadata) -> ast::DefId; } -impl def_id_decoder_helpers for D - where ::Error: Debug +impl def_id_decoder_helpers for D + where ::Error: Debug { fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId { let did: ast::DefId = Decodable::decode(self).unwrap(); @@ -615,7 +615,7 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, autoderef: u32, method: &MethodCallee<'tcx>) { - use serialize::Encoder; + use rustc_serialize::Encoder; rbml_w.emit_struct("MethodCallee", 4, |rbml_w| { rbml_w.emit_struct_field("autoderef", 0, |rbml_w| { @@ -782,7 +782,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { ecx: &e::EncodeContext<'b, 'tcx>, method_origin: &ty::MethodOrigin<'tcx>) { - use serialize::Encoder; + use rustc_serialize::Encoder; self.emit_enum("MethodOrigin", |this| { match *method_origin { @@ -805,7 +805,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { Ok(this.emit_trait_ref(ecx, &p.trait_ref)) })); try!(this.emit_struct_field("method_num", 0, |this| { - this.emit_uint(p.method_num) + this.emit_usize(p.method_num) })); try!(this.emit_struct_field("impl_def_id", 0, |this| { this.emit_option(|this| { @@ -832,10 +832,10 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { Ok(this.emit_def_id(o.object_trait_id)) })); try!(this.emit_struct_field("method_num", 0, |this| { - this.emit_uint(o.method_num) + this.emit_usize(o.method_num) })); try!(this.emit_struct_field("vtable_index", 0, |this| { - this.emit_uint(o.vtable_index) + this.emit_usize(o.vtable_index) })); Ok(()) }) @@ -879,7 +879,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { fn emit_type_scheme<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, type_scheme: ty::TypeScheme<'tcx>) { - use serialize::Encoder; + use rustc_serialize::Encoder; self.emit_struct("TypeScheme", 2, |this| { this.emit_struct_field("generics", 0, |this| { @@ -924,7 +924,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { fn emit_auto_adjustment<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, adj: &ty::AutoAdjustment<'tcx>) { - use serialize::Encoder; + use rustc_serialize::Encoder; self.emit_enum("AutoAdjustment", |this| { match *adj { @@ -949,7 +949,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { } fn emit_autoref<'b>(&mut self, autoref: &ty::AutoRef<'tcx>) { - use serialize::Encoder; + use rustc_serialize::Encoder; self.emit_enum("AutoRef", |this| { match autoref { @@ -970,7 +970,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { fn emit_auto_deref_ref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, auto_deref_ref: &ty::AutoDerefRef<'tcx>) { - use serialize::Encoder; + use rustc_serialize::Encoder; self.emit_struct("AutoDerefRef", 2, |this| { this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this)); @@ -1296,7 +1296,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }, method_num: { this.read_struct_field("method_num", 1, |this| { - this.read_uint() + this.read_usize() }).unwrap() }, impl_def_id: { @@ -1330,12 +1330,12 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }, method_num: { this.read_struct_field("method_num", 2, |this| { - this.read_uint() + this.read_usize() }).unwrap() }, vtable_index: { this.read_struct_field("vtable_index", 3, |this| { - this.read_uint() + this.read_usize() }).unwrap() }, })) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 48fe574e71f48..43103b226c11b 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -688,162 +688,80 @@ pub fn build_target_config(opts: &Options, sp: &SpanHandler) -> Config { } /// Returns the "short" subset of the stable rustc command line options. -pub fn short_optgroups() -> Vec { - rustc_short_optgroups().into_iter() - .filter(|g|g.is_stable()) - .map(|g|g.opt_group) - .collect() -} - -/// Returns all of the stable rustc command line options. -pub fn optgroups() -> Vec { - rustc_optgroups().into_iter() - .filter(|g|g.is_stable()) - .map(|g|g.opt_group) - .collect() -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum OptionStability { Stable, Unstable } - -#[derive(Clone, PartialEq, Eq)] -pub struct RustcOptGroup { - pub opt_group: getopts::OptGroup, - pub stability: OptionStability, -} - -impl RustcOptGroup { - pub fn is_stable(&self) -> bool { - self.stability == OptionStability::Stable - } - - fn stable(g: getopts::OptGroup) -> RustcOptGroup { - RustcOptGroup { opt_group: g, stability: OptionStability::Stable } - } - - fn unstable(g: getopts::OptGroup) -> RustcOptGroup { - RustcOptGroup { opt_group: g, stability: OptionStability::Unstable } - } -} - -// The `opt` local module holds wrappers around the `getopts` API that -// adds extra rustc-specific metadata to each option; such metadata -// is exposed by . The public -// functions below ending with `_u` are the functions that return -// *unstable* options, i.e. options that are only enabled when the -// user also passes the `-Z unstable-options` debugging flag. -mod opt { - // The `fn opt_u` etc below are written so that we can use them - // in the future; do not warn about them not being used right now. - #![allow(dead_code)] - - use getopts; - use super::RustcOptGroup; - - pub type R = RustcOptGroup; - pub type S<'a> = &'a str; - - fn stable(g: getopts::OptGroup) -> R { RustcOptGroup::stable(g) } - fn unstable(g: getopts::OptGroup) -> R { RustcOptGroup::unstable(g) } - - // FIXME (pnkfelix): We default to stable since the current set of - // options is defacto stable. However, it would be good to revise the - // code so that a stable option is the thing that takes extra effort - // to encode. - - pub fn opt(a: S, b: S, c: S, d: S) -> R { stable(getopts::optopt(a, b, c, d)) } - pub fn multi(a: S, b: S, c: S, d: S) -> R { stable(getopts::optmulti(a, b, c, d)) } - pub fn flag(a: S, b: S, c: S) -> R { stable(getopts::optflag(a, b, c)) } - pub fn flagopt(a: S, b: S, c: S, d: S) -> R { stable(getopts::optflagopt(a, b, c, d)) } - pub fn flagmulti(a: S, b: S, c: S) -> R { stable(getopts::optflagmulti(a, b, c)) } - - - pub fn opt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optopt(a, b, c, d)) } - pub fn multi_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optmulti(a, b, c, d)) } - pub fn flag_u(a: S, b: S, c: S) -> R { unstable(getopts::optflag(a, b, c)) } - pub fn flagopt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optflagopt(a, b, c, d)) } - pub fn flagmulti_u(a: S, b: S, c: S) -> R { unstable(getopts::optflagmulti(a, b, c)) } -} - -/// Returns the "short" subset of the rustc command line options, -/// including metadata for each option, such as whether the option is -/// part of the stable long-term interface for rustc. -pub fn rustc_short_optgroups() -> Vec { - vec![ - opt::flag("h", "help", "Display this message"), - opt::multi("", "cfg", "Configure the compilation environment", "SPEC"), - opt::multi("L", "", "Add a directory to the library search path", - "[KIND=]PATH"), - opt::multi("l", "", "Link the generated crate(s) to the specified native +pub fn short_optgroups(options: &mut getopts::Options) { + options.optflag("h", "help", "Display this message") + .optmulti("", "cfg", "Configure the compilation environment", "SPEC") + .optmulti("L", "", "Add a directory to the library search path", + "[KIND=]PATH") + .optmulti("l", "", "Link the generated crate(s) to the specified native library NAME. The optional KIND can be one of, static, dylib, or framework. If omitted, dylib is - assumed.", "[KIND=]NAME"), - opt::multi("", "crate-type", "Comma separated list of types of crates + assumed.", "[KIND=]NAME") + .optmulti("", "crate-type", "Comma separated list of types of crates for the compiler to emit", - "[bin|lib|rlib|dylib|staticlib]"), - opt::opt("", "crate-name", "Specify the name of the crate being built", - "NAME"), - opt::multi("", "emit", "Comma separated list of types of output for \ + "[bin|lib|rlib|dylib|staticlib]") + .optopt("", "crate-name", "Specify the name of the crate being built", + "NAME") + .optmulti("", "emit", "Comma separated list of types of output for \ the compiler to emit", - "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"), - opt::multi("", "print", "Comma separated list of compiler information to \ + "[asm|llvm-bc|llvm-ir|obj|link|dep-info]") + .optmulti("", "print", "Comma separated list of compiler information to \ print on stdout", - "[crate-name|file-names|sysroot]"), - opt::flagmulti("g", "", "Equivalent to -C debuginfo=2"), - opt::flagmulti("O", "", "Equivalent to -C opt-level=2"), - opt::opt("o", "", "Write output to ", "FILENAME"), - opt::opt("", "out-dir", "Write output to compiler-chosen filename \ - in ", "DIR"), - opt::opt("", "explain", "Provide a detailed explanation of an error \ - message", "OPT"), - opt::flag("", "test", "Build a test harness"), - opt::opt("", "target", "Target triple cpu-manufacturer-kernel[-os] \ + "[crate-name|file-names|sysroot]") + .optflagmulti("g", "", "Equivalent to -C debuginfo=2") + .optflagmulti("O", "", "Equivalent to -C opt-level=2") + .optopt("o", "", "Write output to ", "FILENAME") + .optopt("", "out-dir", "Write output to compiler-chosen filename \ + in ", "DIR") + .optopt("", "explain", "Provide a detailed explanation of an error \ + message", "OPT") + .optflag("", "test", "Build a test harness") + .optopt("", "target", "Target triple cpu-manufacturer-kernel[-os] \ to compile for (see chapter 3.4 of \ http://www.sourceware.org/autobook/ for details)", - "TRIPLE"), - opt::multi("W", "warn", "Set lint warnings", "OPT"), - opt::multi("A", "allow", "Set lint allowed", "OPT"), - opt::multi("D", "deny", "Set lint denied", "OPT"), - opt::multi("F", "forbid", "Set lint forbidden", "OPT"), - opt::multi("C", "codegen", "Set a codegen option", "OPT[=VALUE]"), - opt::flag("V", "version", "Print version info and exit"), - opt::flag("v", "verbose", "Use verbose output"), - ] + "TRIPLE") + .optmulti("W", "warn", "Set lint warnings", "OPT") + .optmulti("A", "allow", "Set lint allowed", "OPT") + .optmulti("D", "deny", "Set lint denied", "OPT") + .optmulti("F", "forbid", "Set lint forbidden", "OPT") + .optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]") + .optflag("V", "version", "Print version info and exit") + .optflag("v", "verbose", "Use verbose output"); } -/// Returns all rustc command line options, including metadata for -/// each option, such as whether the option is part of the stable -/// long-term interface for rustc. -pub fn rustc_optgroups() -> Vec { - let mut opts = rustc_short_optgroups(); - opts.push_all(&[ - opt::multi("", "extern", "Specify where an external rust library is \ +/// Returns all of the stable rustc command line options. +pub fn optgroups(options: &mut getopts::Options, unstable: bool) { + short_optgroups(options); + options + .optmulti("", "extern", "Specify where an external rust library is \ located", - "NAME=PATH"), - opt::opt("", "sysroot", "Override the system root", "PATH"), - opt::multi("Z", "", "Set internal debugging options", "FLAG"), - opt::opt("", "color", "Configure coloring of output: + "NAME=PATH") + .optopt("", "sysroot", "Override the system root", "PATH") + .optmulti("Z", "", "Set internal debugging options", "FLAG") + .optopt("", "color", "Configure coloring of output: auto = colorize, if output goes to a tty (default); always = always colorize output; - never = never colorize output", "auto|always|never"), - - opt::flagopt_u("", "pretty", - "Pretty-print the input instead of compiling; - valid types are: `normal` (un-annotated source), - `expanded` (crates expanded), - `typed` (crates expanded, with type annotations), or - `expanded,identified` (fully parenthesized, AST nodes with IDs).", - "TYPE"), - opt::flagopt_u("", "xpretty", - "Pretty-print the input instead of compiling, unstable variants; - valid types are any of the types for `--pretty`, as well as: - `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"), - ]); - opts + never = never colorize output", "auto|always|never"); + + if unstable { + options + .optflagopt("", "pretty", + "Pretty-print the input instead of compiling; + valid types are: `normal` (un-annotated source) + `expanded` (crates expanded) + `typed` (crates expanded, with type annotations), or + `expanded,identified` (fully parenthesized, AST nodes with IDs).", + "TYPE") + .optflagopt("", "xpretty", + "Pretty-print the input instead of compiling, unstable variants; + valid types are any of the types for `--pretty`, as well as: + `flowgraph=` (graphviz formatted flowgraph for node), or + `everybody_loops` (all function bodies replaced with `loop {}`).", + "TYPE") + .optopt("", "show-span", "Show spans for compiler debugging", + "expr|pat|ty"); + } } // Convert strings provided as --cfg [cfgspec] into a crate_cfg @@ -1120,7 +1038,7 @@ mod tests { use session::config::{build_configuration, optgroups, build_session_options}; use session::build_session; - use getopts::getopts; + use getopts; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::diagnostics; @@ -1128,11 +1046,12 @@ mod tests { // When the user supplies --test we should implicitly supply --cfg test #[test] fn test_switch_implies_cfg_test() { - let matches = - &match getopts(&["--test".to_string()], &optgroups()) { - Ok(m) => m, - Err(f) => panic!("test_switch_implies_cfg_test: {}", f) - }; + let mut options = getopts::Options::new(); + optgroups(&mut options, false); + let matches = &match options.parse(&["--test"]) { + Ok(m) => m, + Err(f) => panic!("test_switch_implies_cfg_test: {}", f) + }; let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(matches); let sess = build_session(sessopts, None, registry); @@ -1144,14 +1063,14 @@ mod tests { // another --cfg test #[test] fn test_switch_implies_cfg_test_unless_cfg_test() { - let matches = - &match getopts(&["--test".to_string(), "--cfg=test".to_string()], - &optgroups()) { - Ok(m) => m, - Err(f) => { + let mut options = getopts::Options::new(); + optgroups(&mut options, false); + let matches = &match options.parse(&["--test", "--cfg=test"]) { + Ok(m) => m, + Err(f) => { panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f) - } - }; + } + }; let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(matches); let sess = build_session(sessopts, None, registry); @@ -1163,10 +1082,10 @@ mod tests { #[test] fn test_can_print_warnings() { + let mut options = getopts::Options::new(); + optgroups(&mut options, false); { - let matches = getopts(&[ - "-Awarnings".to_string() - ], &optgroups()).unwrap(); + let matches = options.parse(&[ "-Awarnings" ]).unwrap(); let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(&matches); let sess = build_session(sessopts, None, registry); @@ -1174,10 +1093,10 @@ mod tests { } { - let matches = getopts(&[ - "-Awarnings".to_string(), - "-Dwarnings".to_string() - ], &optgroups()).unwrap(); + let matches = options.parse(&[ + "-Awarnings", + "-Dwarnings", + ]).unwrap(); let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(&matches); let sess = build_session(sessopts, None, registry); @@ -1185,9 +1104,9 @@ mod tests { } { - let matches = getopts(&[ - "-Adead_code".to_string() - ], &optgroups()).unwrap(); + let matches = options.parse(&[ + "-Adead_code", + ]).unwrap(); let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(&matches); let sess = build_session(sessopts, None, registry); diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 7d46cc84fd685..f9cef0547fe92 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -46,7 +46,7 @@ extern crate syntax; extern crate libc; -extern crate serialize; +extern crate rustc_serialize; extern crate rustc_llvm; #[macro_use] extern crate log; diff --git a/src/librustc_back/sha2.rs b/src/librustc_back/sha2.rs index 9ed827da8b2e4..d030c1eccefec 100644 --- a/src/librustc_back/sha2.rs +++ b/src/librustc_back/sha2.rs @@ -14,7 +14,7 @@ use std::iter::repeat; use std::slice::bytes::{MutableByteVector, copy_memory}; -use serialize::hex::ToHex; +use rustc_serialize::hex::ToHex; /// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian /// format. @@ -532,7 +532,7 @@ mod tests { use self::rand::Rng; use self::rand::isaac::IsaacRng; - use serialize::hex::FromHex; + use rustc_serialize::hex::FromHex; use std::iter::repeat; use std::u64; use super::{Digest, Sha256, FixedBuffer}; diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 22d966014da1c..ad2a65c1c0e85 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -45,7 +45,7 @@ //! settings, though `target-feature` and `link-args` will *add* to the list //! specified by the target, rather than replace. -use serialize::json::Json; +use rustc_serialize::json::Json; use std::default::Default; use std::io::prelude::*; use syntax::{diagnostic, abi}; @@ -310,14 +310,12 @@ impl Target { use std::ffi::OsString; use std::fs::File; use std::path::{Path, PathBuf}; - use serialize::json; fn load_file(path: &Path) -> Result { let mut f = try!(File::open(path).map_err(|e| e.to_string())); - let mut contents = Vec::new(); - try!(f.read_to_end(&mut contents).map_err(|e| e.to_string())); - let obj = try!(json::from_reader(&mut &contents[..]) - .map_err(|e| e.to_string())); + let mut contents = String::new(); + try!(f.read_to_string(&mut contents).map_err(|e| e.to_string())); + let obj = try!(contents.parse::().map_err(|e| e.to_string())); Ok(Target::from_json(obj)) } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1f8f7694ff90d..9cbe7a5376ed2 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -31,7 +31,7 @@ #![cfg_attr(test, feature(test))] #[macro_use] extern crate log; -extern crate serialize as rustc_serialize; // used by deriving +extern crate rustc_serialize; pub mod snapshot_vec; pub mod graph; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 13dec30e0a016..3b7f5834cc179 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -29,7 +29,7 @@ use rustc_typeck as typeck; use rustc_privacy; use super::Compilation; -use serialize::json; +use rustc_serialize::json; use std::env; use std::ffi::OsString; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 49879b472feb7..07faf2825e428 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -48,7 +48,7 @@ extern crate rustc_privacy; extern crate rustc_resolve; extern crate rustc_trans; extern crate rustc_typeck; -extern crate serialize; +extern crate rustc_serialize; extern crate rustc_llvm as llvm; #[macro_use] extern crate log; #[macro_use] extern crate syntax; @@ -500,15 +500,12 @@ pub fn version(binary: &str, matches: &getopts::Matches) { } fn usage(verbose: bool, include_unstable_options: bool) { - let groups = if verbose { - config::rustc_optgroups() + let mut opts = getopts::Options::new(); + if verbose { + config::optgroups(&mut opts, include_unstable_options) } else { - config::rustc_short_optgroups() - }; - let groups : Vec<_> = groups.into_iter() - .filter(|x| include_unstable_options || x.is_stable()) - .map(|x|x.opt_group) - .collect(); + config::short_optgroups(&mut opts) + } let message = format!("Usage: rustc [OPTIONS] INPUT"); let extra_help = if verbose { "" @@ -520,7 +517,7 @@ Additional help: -C help Print codegen options -W help Print 'lint' options and default settings -Z help Print internal options for debugging rustc{}\n", - getopts::usage(&message, &groups), + opts.usage(&message), extra_help); } @@ -683,49 +680,25 @@ pub fn handle_options(mut args: Vec) -> Option { r.iter().any(|x| *x == "unstable-options") } - fn parse_all_options(args: &Vec) -> getopts::Matches { - let all_groups : Vec - = config::rustc_optgroups().into_iter().map(|x|x.opt_group).collect(); - match getopts::getopts(&args[..], &all_groups) { - Ok(m) => { - if !allows_unstable_options(&m) { - // If -Z unstable-options was not specified, verify that - // no unstable options were present. - for opt in config::rustc_optgroups().into_iter().filter(|x| !x.is_stable()) { - let opt_name = if !opt.opt_group.long_name.is_empty() { - &opt.opt_group.long_name - } else { - &opt.opt_group.short_name - }; - if m.opt_present(opt_name) { - early_error(&format!("use of unstable option '{}' requires \ - -Z unstable-options", opt_name)); - } - } - } - m - } - Err(f) => early_error(&f.to_string()) + let mut stable_options = getopts::Options::new(); + config::optgroups(&mut stable_options, false); + let mut unstable_options = getopts::Options::new(); + config::optgroups(&mut unstable_options, true); + + // Parse using unstable options first to make sure we can parse at all. If + // unstable options are enabled, then we're done, but if unstable options + // are enabled when then also ensure that we can parse with stable options, + // generating an error if this is not the case + let matches = unstable_options.parse(&args).map(|matches| { + if allows_unstable_options(&matches) { + return matches } - } - - // As a speed optimization, first try to parse the command-line using just - // the stable options. - let matches = match getopts::getopts(&args[..], &config::optgroups()) { - Ok(ref m) if allows_unstable_options(m) => { - // If -Z unstable-options was specified, redo parsing with the - // unstable options to ensure that unstable options are defined - // in the returned getopts::Matches. - parse_all_options(&args) - } - Ok(m) => m, - Err(_) => { - // redo option parsing, including unstable options this time, - // in anticipation that the mishandled option was one of the - // unstable ones. - parse_all_options(&args) - } - }; + stable_options.parse(&args).unwrap_or_else(|_| { + early_error("use of unstable option requires -Z unstable-options") + }) + }).unwrap_or_else(|err| { + early_error(&err.to_string()) + }); if matches.opt_present("h") || matches.opt_present("help") { usage(matches.opt_present("verbose"), allows_unstable_options(&matches)); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index c416a9810eb0e..55208fe9889fe 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -36,7 +36,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::str; use flate; -use serialize::hex::ToHex; +use rustc_serialize::hex::ToHex; use syntax::ast; use syntax::ast_map::{PathElem, PathElems, PathName}; use syntax::attr::AttrMetaMethods; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index f25c6eb21a47b..f1c7d6b47c77e 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -51,7 +51,7 @@ extern crate graphviz; extern crate libc; extern crate rustc; extern crate rustc_back; -extern crate serialize; +extern crate rustc_serialize; extern crate rustc_llvm as llvm; #[macro_use] extern crate log; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c4f2c7207ac39..4049af3810859 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -51,7 +51,7 @@ use std::sync::Arc; use externalfiles::ExternalHtml; -use serialize::json::{self, ToJson}; +use rustc_serialize::json::{self, ToJson}; use syntax::{abi, ast, ast_util, attr}; use rustc::util::nodemap::NodeSet; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 38cc120698431..e93ae381b6d37 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -44,14 +44,12 @@ extern crate rustc_driver; extern crate rustc_resolve; extern crate rustc_lint; extern crate rustc_back; -extern crate serialize; +extern crate rustc_serialize; extern crate syntax; extern crate test as testing; extern crate rustc_unicode; #[macro_use] extern crate log; -extern crate serialize as rustc_serialize; // used by deriving - use std::cell::RefCell; use std::collections::HashMap; use std::env; @@ -62,8 +60,8 @@ use std::rc::Rc; use std::sync::mpsc::channel; use externalfiles::ExternalHtml; -use serialize::Decodable; -use serialize::json::{self, Json}; +use rustc_serialize::Decodable; +use rustc_serialize::json::{self, Json}; use rustc::session::search_paths::SearchPaths; // reexported from `clean` so it can be easily updated with the mod itself @@ -134,62 +132,60 @@ pub fn main() { env::set_exit_status(res as i32); } -pub fn opts() -> Vec { - use getopts::*; - vec!( - optflag("h", "help", "show this help message"), - optflag("V", "version", "print rustdoc's version"), - optflag("v", "verbose", "use verbose output"), - optopt("r", "input-format", "the input type of the specified file", - "[rust|json]"), - optopt("w", "output-format", "the output type to write", - "[html|json]"), - optopt("o", "output", "where to place the output", "PATH"), - optopt("", "crate-name", "specify the name of this crate", "NAME"), - optmulti("L", "library-path", "directory to add to crate search path", - "DIR"), - optmulti("", "cfg", "pass a --cfg to rustc", ""), - optmulti("", "extern", "pass an --extern to rustc", "NAME=PATH"), - optmulti("", "plugin-path", "directory to load plugins from", "DIR"), - optmulti("", "passes", "list of passes to also run, you might want \ +pub fn opts(options: &mut getopts::Options) { + options + .optflag("h", "help", "show this help message") + .optflag("V", "version", "print rustdoc's version") + .optflag("v", "verbose", "use verbose output") + .optopt("r", "input-format", "the input type of the specified file", + "[rust|json]") + .optopt("w", "output-format", "the output type to write", + "[html|json]") + .optopt("o", "output", "where to place the output", "PATH") + .optopt("", "crate-name", "specify the name of this crate", "NAME") + .optmulti("L", "library-path", "directory to add to crate search path", + "DIR") + .optmulti("", "cfg", "pass a --cfg to rustc", "") + .optmulti("", "extern", "pass an --extern to rustc", "NAME=PATH") + .optmulti("", "plugin-path", "directory to load plugins from", "DIR") + .optmulti("", "passes", "list of passes to also run, you might want \ to pass it multiple times; a value of `list` \ will print available passes", - "PASSES"), - optmulti("", "plugins", "space separated list of plugins to also load", - "PLUGINS"), - optflag("", "no-defaults", "don't run the default passes"), - optflag("", "test", "run code examples as tests"), - optmulti("", "test-args", "arguments to pass to the test runner", - "ARGS"), - optopt("", "target", "target triple to document", "TRIPLE"), - optmulti("", "markdown-css", "CSS files to include via in a rendered Markdown file", - "FILES"), - optmulti("", "html-in-header", + "PASSES") + .optmulti("", "plugins", "space separated list of plugins to also load", + "PLUGINS") + .optflag("", "no-defaults", "don't run the default passes") + .optflag("", "test", "run code examples as tests") + .optmulti("", "test-args", "arguments to pass to the test runner", + "ARGS") + .optopt("", "target", "target triple to document", "TRIPLE") + .optmulti("", "markdown-css", "CSS files to include via in a rendered Markdown file", + "FILES") + .optmulti("", "html-in-header", "files to include inline in the section of a rendered Markdown file \ or generated documentation", - "FILES"), - optmulti("", "html-before-content", + "FILES") + .optmulti("", "html-before-content", "files to include inline between and the content of a rendered \ Markdown file or generated documentation", - "FILES"), - optmulti("", "html-after-content", + "FILES") + .optmulti("", "html-after-content", "files to include inline between the content and of a rendered \ Markdown file or generated documentation", - "FILES"), - optopt("", "markdown-playground-url", - "URL to send code snippets to", "URL"), - optflag("", "markdown-no-toc", "don't include table of contents") - ) + "FILES") + .optopt("", "markdown-playground-url", + "URL to send code snippets to", "URL") + .optflag("", "markdown-no-toc", "don't include table of contents"); } -pub fn usage(argv0: &str) { - println!("{}", - getopts::usage(&format!("{} [options] ", argv0), - &opts())); +pub fn usage(argv0: &str, options: &getopts::Options) { + println!("{}", options.usage(&format!("{} [options] ", argv0))); } pub fn main_args(args: &[String]) -> isize { - let matches = match getopts::getopts(args.tail(), &opts()) { + let mut options = getopts::Options::new(); + opts(&mut options); + let matches = match options.parse(args.tail()) { Ok(m) => m, Err(err) => { println!("{}", err); @@ -197,7 +193,7 @@ pub fn main_args(args: &[String]) -> isize { } }; if matches.opt_present("h") || matches.opt_present("help") { - usage(&args[0]); + usage(&args[0], &options); return 0; } else if matches.opt_present("version") { rustc_driver::version("rustdoc", &matches); @@ -456,12 +452,12 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche /// This input format purely deserializes the json output file. No passes are /// run over the deserialized output. fn json_input(input: &str) -> Result { - let mut bytes = Vec::new(); - match File::open(input).and_then(|mut f| f.read_to_end(&mut bytes)) { + let mut contents = String::new(); + match File::open(input).and_then(|mut f| f.read_to_string(&mut contents)) { Ok(_) => {} Err(e) => return Err(format!("couldn't open {}: {}", input, e)), }; - match json::from_reader(&mut &bytes[..]) { + match contents.parse() { Err(s) => Err(format!("{:?}", s)), Ok(Json::Object(obj)) => { let mut obj = obj; @@ -520,7 +516,7 @@ fn json_output(krate: clean::Crate, res: Vec , // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode // straight to the Rust JSON representation. let crate_json_str = format!("{}", json::as_json(&krate)); - let crate_json = match json::from_str(&crate_json_str) { + let crate_json = match crate_json_str.parse() { Ok(j) => j, Err(e) => panic!("Rust generated JSON is invalid: {:?}", e) }; diff --git a/src/librustdoc/plugins.rs b/src/librustdoc/plugins.rs index d4d214f449d59..de49003436b5f 100644 --- a/src/librustdoc/plugins.rs +++ b/src/librustdoc/plugins.rs @@ -13,7 +13,7 @@ use clean; use std::dynamic_lib as dl; -use serialize::json; +use rustc_serialize::json; use std::mem; use std::string::String; use std::path::PathBuf; diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs deleted file mode 100644 index 31790ce6290fe..0000000000000 --- a/src/libserialize/lib.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Support code for encoding and decoding types. - -/* -Core encoding and decoding interfaces. -*/ - -// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) -#![cfg_attr(stage0, feature(custom_attribute))] -#![crate_name = "serialize"] -#![unstable(feature = "rustc_private", - reason = "deprecated in favor of rustc-serialize on crates.io")] -#![staged_api] -#![crate_type = "rlib"] -#![crate_type = "dylib"] -#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "http://doc.rust-lang.org/nightly/", - html_playground_url = "http://play.rust-lang.org/")] - -#![feature(box_syntax)] -#![feature(collections)] -#![feature(core)] -#![feature(rustc_private)] -#![feature(staged_api)] -#![feature(std_misc)] -#![feature(unicode)] -#![feature(str_char)] -#![cfg_attr(test, feature(test))] - -// test harness access -#[cfg(test)] extern crate test; -#[macro_use] extern crate log; - -extern crate rustc_unicode; -extern crate collections; - -pub use self::serialize::{Decoder, Encoder, Decodable, Encodable, - DecoderHelpers, EncoderHelpers}; - -mod serialize; -mod collection_impls; - -pub mod hex; -pub mod json; - -mod rustc_serialize { - pub use serialize::*; -} diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 5b03b3bf0385c..783c1585d274a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -67,7 +67,7 @@ use ptr::P; use std::fmt; use std::rc::Rc; -use serialize::{Encodable, Decodable, Encoder, Decoder}; +use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; // FIXME #6993: in librustc, uses of "ident" should be replaced // by just "Name". @@ -1879,13 +1879,13 @@ pub struct MacroDef { #[cfg(test)] mod tests { - use serialize; + use rustc_serialize; use super::*; // are ASTs encodable? #[test] fn check_asts_encodable() { - fn assert_encodable() {} + fn assert_encodable() {} assert_encodable::(); } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index b2a366ec5beb6..8c81b940fc013 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -27,7 +27,7 @@ use std::rc::Rc; use std::{fmt, fs}; use std::io::{self, Read}; -use serialize::{Encodable, Decodable, Encoder, Decoder}; +use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; // _____________________________________________________________________________ diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 718bc1773fe59..53bfb5efc02ba 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -20,7 +20,7 @@ use std::cell::{RefCell, Cell}; use std::{cmp, error, fmt}; use std::io::prelude::*; use std::io; -use term::{self, WriterWrapper}; +use term; use libc; /// maximum number of lines we will print for each error; arbitrary. @@ -310,7 +310,7 @@ impl Level { fn print_maybe_styled(w: &mut EmitterWriter, msg: &str, - color: term::attr::Attr) -> io::Result<()> { + color: term::Attr) -> io::Result<()> { match w.dst { Terminal(ref mut t) => { try!(t.attr(color)); @@ -349,14 +349,14 @@ fn print_diagnostic(dst: &mut EmitterWriter, topic: &str, lvl: Level, try!(print_maybe_styled(dst, &format!("{}: ", lvl.to_string()), - term::attr::ForegroundColor(lvl.color()))); + term::Attr::ForegroundColor(lvl.color()))); try!(print_maybe_styled(dst, &format!("{}", msg), - term::attr::Bold)); + term::Attr::Bold)); match code { Some(code) => { - let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA); + let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA); try!(print_maybe_styled(dst, &format!(" [{}]", code.clone()), style)); } None => () @@ -371,7 +371,7 @@ pub struct EmitterWriter { } enum Destination { - Terminal(Box + Send>), + Terminal(Box + Send>), Raw(Box), } @@ -679,7 +679,7 @@ fn highlight_lines(err: &mut EmitterWriter, try!(print_maybe_styled(err, &format!("{}\n", s), - term::attr::ForegroundColor(lvl.color()))); + term::Attr::ForegroundColor(lvl.color()))); } } Ok(()) @@ -754,7 +754,7 @@ fn end_highlight_lines(w: &mut EmitterWriter, s.push('\n'); print_maybe_styled(w, &s[..], - term::attr::ForegroundColor(lvl.color())) + term::Attr::ForegroundColor(lvl.color())) } fn print_macro_backtrace(w: &mut EmitterWriter, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 20f8c9707bfdd..7541a982f6c8f 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -37,14 +37,12 @@ extern crate arena; extern crate fmt_macros; -extern crate serialize; +extern crate rustc_serialize; extern crate term; extern crate libc; #[macro_use] extern crate log; #[macro_use] #[no_link] extern crate rustc_bitflags; -extern crate serialize as rustc_serialize; // used by deriving - // A variant of 'try!' that panics on Err(FatalError). This is used as a // crutch on the way towards a non-panic!-prone parser. It should be used // for fatal parsing errors; eventually we plan to convert all code using diff --git a/src/libsyntax/owned_slice.rs b/src/libsyntax/owned_slice.rs index 25f1f9b8480a1..eaecce4ed80d0 100644 --- a/src/libsyntax/owned_slice.rs +++ b/src/libsyntax/owned_slice.rs @@ -13,7 +13,7 @@ use std::fmt; use std::iter::{IntoIterator, FromIterator}; use std::ops::Deref; use std::vec; -use serialize::{Encodable, Decodable, Encoder, Decoder}; +use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; /// A non-growable owned slice. This is a separate type to allow the /// representation to change. diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 832fec40199b8..2ff1d7a356580 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -21,7 +21,7 @@ use ptr::P; use util::interner::{RcStr, StrInterner}; use util::interner; -use serialize::{Decodable, Decoder, Encodable, Encoder}; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; use std::ops::Deref; use std::rc::Rc; diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 83e321f110c58..e06f487e604ed 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -41,7 +41,7 @@ use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::ptr; -use serialize::{Encodable, Decodable, Encoder, Decoder}; +use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; /// An owned smart pointer. pub struct P { diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs deleted file mode 100644 index ec1426e6e48ce..0000000000000 --- a/src/libterm/lib.rs +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Terminal formatting library. -//! -//! This crate provides the `Terminal` trait, which abstracts over an [ANSI -//! Terminal][ansi] to provide color printing, among other things. There are two implementations, -//! the `TerminfoTerminal`, which uses control characters from a -//! [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console -//! API][win]. -//! -//! # Examples -//! -//! ```no_run -//! # #![feature(rustc_private)] -//! extern crate term; -//! -//! use std::io::prelude::*; -//! -//! fn main() { -//! let mut t = term::stdout().unwrap(); -//! -//! t.fg(term::color::GREEN).unwrap(); -//! (write!(t, "hello, ")).unwrap(); -//! -//! t.fg(term::color::RED).unwrap(); -//! (writeln!(t, "world!")).unwrap(); -//! -//! t.reset().unwrap(); -//! } -//! ``` -//! -//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code -//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx -//! [ti]: https://en.wikipedia.org/wiki/Terminfo - -// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) -#![cfg_attr(stage0, feature(custom_attribute))] -#![crate_name = "term"] -#![unstable(feature = "rustc_private", - reason = "use the crates.io `term` library instead")] -#![staged_api] -#![crate_type = "rlib"] -#![crate_type = "dylib"] -#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "http://doc.rust-lang.org/nightly/", - html_playground_url = "http://play.rust-lang.org/")] -#![deny(missing_docs)] - -#![feature(box_syntax)] -#![feature(collections)] -#![feature(rustc_private)] -#![feature(staged_api)] -#![feature(std_misc)] -#![feature(str_char)] -#![feature(path_ext)] -#![cfg_attr(windows, feature(libc))] - -#[macro_use] extern crate log; - -pub use terminfo::TerminfoTerminal; -#[cfg(windows)] -pub use win::WinConsole; - -use std::io::prelude::*; -use std::io; - -pub mod terminfo; - -#[cfg(windows)] -mod win; - -/// A hack to work around the fact that `Box` does not -/// currently implement `Write`. -pub struct WriterWrapper { - wrapped: Box, -} - -impl Write for WriterWrapper { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.wrapped.write(buf) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - self.wrapped.flush() - } -} - -#[cfg(not(windows))] -/// Return a Terminal wrapping stdout, or None if a terminal couldn't be -/// opened. -pub fn stdout() -> Option + Send>> { - TerminfoTerminal::new(WriterWrapper { - wrapped: box std::io::stdout(), - }) -} - -#[cfg(windows)] -/// Return a Terminal wrapping stdout, or None if a terminal couldn't be -/// opened. -pub fn stdout() -> Option + Send>> { - let ti = TerminfoTerminal::new(WriterWrapper { - wrapped: box std::io::stdout(), - }); - - match ti { - Some(t) => Some(t), - None => { - WinConsole::new(WriterWrapper { - wrapped: box std::io::stdout(), - }) - } - } -} - -#[cfg(not(windows))] -/// Return a Terminal wrapping stderr, or None if a terminal couldn't be -/// opened. -pub fn stderr() -> Option + Send>> { - TerminfoTerminal::new(WriterWrapper { - wrapped: box std::io::stderr(), - }) -} - -#[cfg(windows)] -/// Return a Terminal wrapping stderr, or None if a terminal couldn't be -/// opened. -pub fn stderr() -> Option + Send>> { - let ti = TerminfoTerminal::new(WriterWrapper { - wrapped: box std::io::stderr(), - }); - - match ti { - Some(t) => Some(t), - None => { - WinConsole::new(WriterWrapper { - wrapped: box std::io::stderr(), - }) - } - } -} - - -/// Terminal color definitions -pub mod color { - /// Number for a terminal color - pub type Color = u16; - - pub const BLACK: Color = 0; - pub const RED: Color = 1; - pub const GREEN: Color = 2; - pub const YELLOW: Color = 3; - pub const BLUE: Color = 4; - pub const MAGENTA: Color = 5; - pub const CYAN: Color = 6; - pub const WHITE: Color = 7; - - pub const BRIGHT_BLACK: Color = 8; - pub const BRIGHT_RED: Color = 9; - pub const BRIGHT_GREEN: Color = 10; - pub const BRIGHT_YELLOW: Color = 11; - pub const BRIGHT_BLUE: Color = 12; - pub const BRIGHT_MAGENTA: Color = 13; - pub const BRIGHT_CYAN: Color = 14; - pub const BRIGHT_WHITE: Color = 15; -} - -/// Terminal attributes -pub mod attr { - pub use self::Attr::*; - - /// Terminal attributes for use with term.attr(). - /// - /// Most attributes can only be turned on and must be turned off with term.reset(). - /// The ones that can be turned off explicitly take a boolean value. - /// Color is also represented as an attribute for convenience. - #[derive(Copy, Clone)] - pub enum Attr { - /// Bold (or possibly bright) mode - Bold, - /// Dim mode, also called faint or half-bright. Often not supported - Dim, - /// Italics mode. Often not supported - Italic(bool), - /// Underline mode - Underline(bool), - /// Blink mode - Blink, - /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold - Standout(bool), - /// Reverse mode, inverts the foreground and background colors - Reverse, - /// Secure mode, also called invis mode. Hides the printed text - Secure, - /// Convenience attribute to set the foreground color - ForegroundColor(super::color::Color), - /// Convenience attribute to set the background color - BackgroundColor(super::color::Color) - } -} - -/// A terminal with similar capabilities to an ANSI Terminal -/// (foreground/background colors etc). -pub trait Terminal: Write { - /// Sets the foreground color to the given color. - /// - /// If the color is a bright color, but the terminal only supports 8 colors, - /// the corresponding normal color will be used instead. - /// - /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)` - /// if there was an I/O error. - fn fg(&mut self, color: color::Color) -> io::Result; - - /// Sets the background color to the given color. - /// - /// If the color is a bright color, but the terminal only supports 8 colors, - /// the corresponding normal color will be used instead. - /// - /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)` - /// if there was an I/O error. - fn bg(&mut self, color: color::Color) -> io::Result; - - /// Sets the given terminal attribute, if supported. Returns `Ok(true)` - /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if - /// there was an I/O error. - fn attr(&mut self, attr: attr::Attr) -> io::Result; - - /// Returns whether the given terminal attribute is supported. - fn supports_attr(&self, attr: attr::Attr) -> bool; - - /// Resets all terminal attributes and color to the default. - /// Returns `Ok()`. - fn reset(&mut self) -> io::Result<()>; - - /// Gets an immutable reference to the stream inside - fn get_ref<'a>(&'a self) -> &'a T; - - /// Gets a mutable reference to the stream inside - fn get_mut<'a>(&'a mut self) -> &'a mut T; -} - -/// A terminal which can be unwrapped. -pub trait UnwrappableTerminal: Terminal { - /// Returns the contained stream, destroying the `Terminal` - fn unwrap(self) -> T; -} diff --git a/src/libterm/terminfo/mod.rs b/src/libterm/terminfo/mod.rs deleted file mode 100644 index 4840cd1fddadf..0000000000000 --- a/src/libterm/terminfo/mod.rs +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Terminfo database interface. - -use std::collections::HashMap; -use std::env; -use std::io::prelude::*; -use std::io; - -use attr; -use color; -use Terminal; -use UnwrappableTerminal; -use self::searcher::open; -use self::parser::compiled::{parse, msys_terminfo}; -use self::parm::{expand, Number, Variables}; - - -/// A parsed terminfo database entry. -#[derive(Debug)] -pub struct TermInfo { - /// Names for the terminal - pub names: Vec , - /// Map of capability name to boolean value - pub bools: HashMap, - /// Map of capability name to numeric value - pub numbers: HashMap, - /// Map of capability name to raw (unexpanded) string - pub strings: HashMap > -} - -pub mod searcher; - -/// TermInfo format parsing. -pub mod parser { - //! ncurses-compatible compiled terminfo format parsing (term(5)) - pub mod compiled; -} -pub mod parm; - - -fn cap_for_attr(attr: attr::Attr) -> &'static str { - match attr { - attr::Bold => "bold", - attr::Dim => "dim", - attr::Italic(true) => "sitm", - attr::Italic(false) => "ritm", - attr::Underline(true) => "smul", - attr::Underline(false) => "rmul", - attr::Blink => "blink", - attr::Standout(true) => "smso", - attr::Standout(false) => "rmso", - attr::Reverse => "rev", - attr::Secure => "invis", - attr::ForegroundColor(_) => "setaf", - attr::BackgroundColor(_) => "setab" - } -} - -/// A Terminal that knows how many colors it supports, with a reference to its -/// parsed Terminfo database record. -pub struct TerminfoTerminal { - num_colors: u16, - out: T, - ti: Box -} - -impl Terminal for TerminfoTerminal { - fn fg(&mut self, color: color::Color) -> io::Result { - let color = self.dim_if_necessary(color); - if self.num_colors > color { - let s = expand(self.ti - .strings - .get("setaf") - .unwrap() - , - &[Number(color as isize)], &mut Variables::new()); - if s.is_ok() { - try!(self.out.write_all(&s.unwrap())); - return Ok(true) - } - } - Ok(false) - } - - fn bg(&mut self, color: color::Color) -> io::Result { - let color = self.dim_if_necessary(color); - if self.num_colors > color { - let s = expand(self.ti - .strings - .get("setab") - .unwrap() - , - &[Number(color as isize)], &mut Variables::new()); - if s.is_ok() { - try!(self.out.write_all(&s.unwrap())); - return Ok(true) - } - } - Ok(false) - } - - fn attr(&mut self, attr: attr::Attr) -> io::Result { - match attr { - attr::ForegroundColor(c) => self.fg(c), - attr::BackgroundColor(c) => self.bg(c), - _ => { - let cap = cap_for_attr(attr); - let parm = self.ti.strings.get(cap); - if parm.is_some() { - let s = expand(parm.unwrap(), - &[], - &mut Variables::new()); - if s.is_ok() { - try!(self.out.write_all(&s.unwrap())); - return Ok(true) - } - } - Ok(false) - } - } - } - - fn supports_attr(&self, attr: attr::Attr) -> bool { - match attr { - attr::ForegroundColor(_) | attr::BackgroundColor(_) => { - self.num_colors > 0 - } - _ => { - let cap = cap_for_attr(attr); - self.ti.strings.get(cap).is_some() - } - } - } - - fn reset(&mut self) -> io::Result<()> { - let mut cap = self.ti.strings.get("sgr0"); - if cap.is_none() { - // are there any terminals that have color/attrs and not sgr0? - // Try falling back to sgr, then op - cap = self.ti.strings.get("sgr"); - if cap.is_none() { - cap = self.ti.strings.get("op"); - } - } - let s = cap.map_or(Err("can't find terminfo capability `sgr0`".to_string()), |op| { - expand(op, &[], &mut Variables::new()) - }); - if s.is_ok() { - return self.out.write_all(&s.unwrap()) - } - Ok(()) - } - - fn get_ref<'a>(&'a self) -> &'a T { &self.out } - - fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.out } -} - -impl UnwrappableTerminal for TerminfoTerminal { - fn unwrap(self) -> T { self.out } -} - -impl TerminfoTerminal { - /// Returns `None` whenever the terminal cannot be created for some - /// reason. - pub fn new(out: T) -> Option+Send+'static>> { - let term = match env::var("TERM") { - Ok(t) => t, - Err(..) => { - debug!("TERM environment variable not defined"); - return None; - } - }; - - let mut file = match open(&term[..]) { - Ok(f) => f, - Err(err) => return match env::var("MSYSCON") { - Ok(ref val) if &val[..] == "mintty.exe" => { - // msys terminal - Some(box TerminfoTerminal{ - out: out, - ti: msys_terminfo(), - num_colors: 8, - }) - }, - _ => { - debug!("error finding terminfo entry: {:?}", err); - None - }, - }, - }; - - let ti = parse(&mut file, false); - if ti.is_err() { - debug!("error parsing terminfo entry: {:?}", ti.err().unwrap()); - return None; - } - - let inf = ti.unwrap(); - let nc = if inf.strings.get("setaf").is_some() - && inf.strings.get("setab").is_some() { - inf.numbers.get("colors").map_or(0, |&n| n) - } else { 0 }; - - return Some(box TerminfoTerminal {out: out, - ti: inf, - num_colors: nc}); - } - - fn dim_if_necessary(&self, color: color::Color) -> color::Color { - if color >= self.num_colors && color >= 8 && color < 16 { - color-8 - } else { color } - } -} - - -impl Write for TerminfoTerminal { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.out.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.out.flush() - } -} diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs deleted file mode 100644 index 16062060df087..0000000000000 --- a/src/libterm/terminfo/searcher.rs +++ /dev/null @@ -1,119 +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. - -//! ncurses-compatible database discovery -//! -//! Does not support hashed database, only filesystem! - -use std::env; -use std::fs::File; -use std::io::prelude::*; -use std::path::PathBuf; - -/// Return path to database entry for `term` -#[allow(deprecated)] -pub fn get_dbpath_for_term(term: &str) -> Option> { - if term.is_empty() { - return None; - } - - let homedir = env::home_dir(); - - let mut dirs_to_search = Vec::new(); - let first_char = term.char_at(0); - - // Find search directory - match env::var_os("TERMINFO") { - Some(dir) => dirs_to_search.push(PathBuf::from(dir)), - None => { - if homedir.is_some() { - // ncurses compatibility; - dirs_to_search.push(homedir.unwrap().join(".terminfo")) - } - match env::var("TERMINFO_DIRS") { - Ok(dirs) => for i in dirs.split(':') { - if i == "" { - dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); - } else { - dirs_to_search.push(PathBuf::from(i)); - } - }, - // Found nothing in TERMINFO_DIRS, use the default paths: - // According to /etc/terminfo/README, after looking at - // ~/.terminfo, ncurses will search /etc/terminfo, then - // /lib/terminfo, and eventually /usr/share/terminfo. - Err(..) => { - dirs_to_search.push(PathBuf::from("/etc/terminfo")); - dirs_to_search.push(PathBuf::from("/lib/terminfo")); - dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); - } - } - } - }; - - // Look for the terminal in all of the search directories - for p in &dirs_to_search { - if p.exists() { - let f = first_char.to_string(); - let newp = p.join(&f).join(term); - if newp.exists() { - return Some(box newp); - } - // on some installations the dir is named after the hex of the char (e.g. OS X) - let f = format!("{:x}", first_char as usize); - let newp = p.join(&f).join(term); - if newp.exists() { - return Some(box newp); - } - } - } - None -} - -/// Return open file for `term` -pub fn open(term: &str) -> Result { - match get_dbpath_for_term(term) { - Some(x) => { - match File::open(&*x) { - Ok(file) => Ok(file), - Err(e) => Err(format!("error opening file: {:?}", e)), - } - } - None => { - Err(format!("could not find terminfo entry for {:?}", term)) - } - } -} - -#[test] -#[ignore(reason = "buildbots don't have ncurses installed and I can't mock everything I need")] -fn test_get_dbpath_for_term() { - // woefully inadequate test coverage - // note: current tests won't work with non-standard terminfo hierarchies (e.g. OS X's) - use std::env; - // FIXME (#9639): This needs to handle non-utf8 paths - fn x(t: &str) -> String { - let p = get_dbpath_for_term(t).expect("no terminfo entry found"); - p.to_str().unwrap().to_string() - }; - assert!(x("screen") == "/usr/share/terminfo/s/screen"); - assert!(get_dbpath_for_term("") == None); - env::set_var("TERMINFO_DIRS", ":"); - assert!(x("screen") == "/usr/share/terminfo/s/screen"); - env::remove_var("TERMINFO_DIRS"); -} - -#[test] -#[ignore(reason = "see test_get_dbpath_for_term")] -fn test_open() { - open("screen").unwrap(); - let t = open("nonexistent terminal that hopefully does not exist"); - assert!(t.is_err()); -} diff --git a/src/libterm/win.rs b/src/libterm/win.rs deleted file mode 100644 index 66ef5e8661797..0000000000000 --- a/src/libterm/win.rs +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Windows console handling - -// FIXME (#13400): this is only a tiny fraction of the Windows console api - -extern crate libc; - -use std::io; -use std::io::prelude::*; - -use attr; -use color; -use {Terminal,UnwrappableTerminal}; - -/// A Terminal implementation which uses the Win32 Console API. -pub struct WinConsole { - buf: T, - def_foreground: color::Color, - def_background: color::Color, - foreground: color::Color, - background: color::Color, -} - -#[allow(non_snake_case)] -#[repr(C)] -struct CONSOLE_SCREEN_BUFFER_INFO { - dwSize: [libc::c_short; 2], - dwCursorPosition: [libc::c_short; 2], - wAttributes: libc::WORD, - srWindow: [libc::c_short; 4], - dwMaximumWindowSize: [libc::c_short; 2], -} - -#[allow(non_snake_case)] -#[link(name = "kernel32")] -extern "system" { - fn SetConsoleTextAttribute(handle: libc::HANDLE, attr: libc::WORD) -> libc::BOOL; - fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE; - fn GetConsoleScreenBufferInfo(handle: libc::HANDLE, - info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> libc::BOOL; -} - -fn color_to_bits(color: color::Color) -> u16 { - // magic numbers from mingw-w64's wincon.h - - let bits = match color % 8 { - color::BLACK => 0, - color::BLUE => 0x1, - color::GREEN => 0x2, - color::RED => 0x4, - color::YELLOW => 0x2 | 0x4, - color::MAGENTA => 0x1 | 0x4, - color::CYAN => 0x1 | 0x2, - color::WHITE => 0x1 | 0x2 | 0x4, - _ => unreachable!() - }; - - if color >= 8 { - bits | 0x8 - } else { - bits - } -} - -fn bits_to_color(bits: u16) -> color::Color { - let color = match bits & 0x7 { - 0 => color::BLACK, - 0x1 => color::BLUE, - 0x2 => color::GREEN, - 0x4 => color::RED, - 0x6 => color::YELLOW, - 0x5 => color::MAGENTA, - 0x3 => color::CYAN, - 0x7 => color::WHITE, - _ => unreachable!() - }; - - color | (bits & 0x8) // copy the hi-intensity bit -} - -impl WinConsole { - fn apply(&mut self) { - let _unused = self.buf.flush(); - let mut accum: libc::WORD = 0; - accum |= color_to_bits(self.foreground); - accum |= color_to_bits(self.background) << 4; - - unsafe { - // Magic -11 means stdout, from - // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx - // - // You may be wondering, "but what about stderr?", and the answer - // to that is that setting terminal attributes on the stdout - // handle also sets them for stderr, since they go to the same - // terminal! Admittedly, this is fragile, since stderr could be - // redirected to a different console. This is good enough for - // rustc though. See #13400. - let out = GetStdHandle(-11i32 as libc::DWORD); - SetConsoleTextAttribute(out, accum); - } - } - - /// Returns `None` whenever the terminal cannot be created for some - /// reason. - pub fn new(out: T) -> Option+Send+'static>> { - let fg; - let bg; - unsafe { - let mut buffer_info = ::std::mem::uninitialized(); - if GetConsoleScreenBufferInfo(GetStdHandle(-11i32 as libc::DWORD), - &mut buffer_info) != 0 { - fg = bits_to_color(buffer_info.wAttributes); - bg = bits_to_color(buffer_info.wAttributes >> 4); - } else { - fg = color::WHITE; - bg = color::BLACK; - } - } - Some(box WinConsole { buf: out, - def_foreground: fg, def_background: bg, - foreground: fg, background: bg }) - } -} - -impl Write for WinConsole { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.buf.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.buf.flush() - } -} - -impl Terminal for WinConsole { - fn fg(&mut self, color: color::Color) -> io::Result { - self.foreground = color; - self.apply(); - - Ok(true) - } - - fn bg(&mut self, color: color::Color) -> io::Result { - self.background = color; - self.apply(); - - Ok(true) - } - - fn attr(&mut self, attr: attr::Attr) -> io::Result { - match attr { - attr::ForegroundColor(f) => { - self.foreground = f; - self.apply(); - Ok(true) - }, - attr::BackgroundColor(b) => { - self.background = b; - self.apply(); - Ok(true) - }, - _ => Ok(false) - } - } - - fn supports_attr(&self, attr: attr::Attr) -> bool { - // it claims support for underscore and reverse video, but I can't get - // it to do anything -cmr - match attr { - attr::ForegroundColor(_) | attr::BackgroundColor(_) => true, - _ => false - } - } - - fn reset(&mut self) -> io::Result<()> { - self.foreground = self.def_foreground; - self.background = self.def_background; - self.apply(); - - Ok(()) - } - - fn get_ref<'a>(&'a self) -> &'a T { &self.buf } - - fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf } -} - -impl UnwrappableTerminal for WinConsole { - fn unwrap(self) -> T { self.buf } -} diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index da86e727c6874..1de3cefffc42a 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -47,8 +47,7 @@ #![feature(duration_span)] extern crate getopts; -extern crate serialize; -extern crate serialize as rustc_serialize; +extern crate rustc_serialize; extern crate term; extern crate libc; @@ -61,8 +60,7 @@ use self::NamePadding::*; use self::OutputLocation::*; use stats::Stats; -use getopts::{OptGroup, optflag, optopt}; -use serialize::Encodable; +use rustc_serialize::Encodable; use std::boxed::FnBox; use term::Terminal; use term::color::{Color, RED, YELLOW, GREEN, CYAN}; @@ -311,22 +309,23 @@ impl TestOpts { /// Result of parsing the options. pub type OptRes = Result; -fn optgroups() -> Vec { - vec!(getopts::optflag("", "ignored", "Run ignored tests"), - getopts::optflag("", "test", "Run tests and not benchmarks"), - getopts::optflag("", "bench", "Run benchmarks instead of tests"), - getopts::optflag("h", "help", "Display this message (longer with --help)"), - getopts::optopt("", "logfile", "Write logs to the specified file instead \ - of stdout", "PATH"), - getopts::optflag("", "nocapture", "don't capture stdout/stderr of each \ - task, allow printing directly"), - getopts::optopt("", "color", "Configure coloring of output: +fn optgroups(options: &mut getopts::Options) { + options + .optflag("", "ignored", "Run ignored tests") + .optflag("", "test", "Run tests and not benchmarks") + .optflag("", "bench", "Run benchmarks instead of tests") + .optflag("h", "help", "Display this message (longer with --help)") + .optopt("", "logfile", "Write logs to the specified file instead \ + of stdout", "PATH") + .optflag("", "nocapture", "don't capture stdout/stderr of each \ + task, allow printing directly") + .optopt("", "color", "Configure coloring of output: auto = colorize if stdout is a tty and tests are run on serially (default); always = always colorize output; - never = never colorize output;", "auto|always|never")) + never = never colorize output;", "auto|always|never"); } -fn usage(binary: &str) { +fn usage(binary: &str, options: &mut getopts::Options) { let message = format!("Usage: {} [OPTIONS] [FILTER]", binary); println!(r#"{usage} @@ -354,19 +353,20 @@ Test Attributes: test, then the test runner will ignore these tests during normal test runs. Running with --ignored will run these tests."#, - usage = getopts::usage(&message, &optgroups())); + usage = options.usage(&message)); } // Parses command line arguments into test options pub fn parse_opts(args: &[String]) -> Option { let args_ = args.tail(); - let matches = - match getopts::getopts(args_, &optgroups()) { - Ok(m) => m, - Err(f) => return Some(Err(f.to_string())) - }; + let mut options = getopts::Options::new(); + optgroups(&mut options); + let matches = match options.parse(args_) { + Ok(m) => m, + Err(f) => return Some(Err(f.to_string())) + }; - if matches.opt_present("h") { usage(&args[0]); return None; } + if matches.opt_present("h") { usage(&args[0], &mut options); return None; } let filter = if !matches.free.is_empty() { Some(matches.free[0].clone()) @@ -429,7 +429,7 @@ pub enum TestResult { unsafe impl Send for TestResult {} enum OutputLocation { - Pretty(Box + Send>), + Pretty(Box + Send>), Raw(T), } diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index 2d5aae30ae8a9..43985113b21dd 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -53,17 +53,16 @@ struct Config { stress: bool } -fn parse_opts(argv: Vec ) -> Config { - let opts = vec!(getopts::optflag("", "stress", "")); +fn parse_opts(argv: Vec) -> Config { + let mut options = getopts::Options::new(); + options.optflag("", "stress", ""); let argv = argv.iter().map(|x| x.to_string()).collect::>(); let opt_args = &argv[1..argv.len()]; - match getopts::getopts(opt_args, &opts) { - Ok(ref m) => { - return Config {stress: m.opt_present("stress")} - } - Err(_) => { panic!(); } + match options.parse(opt_args) { + Ok(ref m) => Config {stress: m.opt_present("stress")}, + Err(_) => { panic!(); } } } diff --git a/src/test/compile-fail-fulldeps/unstable-crates.rs b/src/test/compile-fail-fulldeps/unstable-crates.rs new file mode 100644 index 0000000000000..a174b1ae735d1 --- /dev/null +++ b/src/test/compile-fail-fulldeps/unstable-crates.rs @@ -0,0 +1,35 @@ +// 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. + +extern crate alloc; //~ ERROR: use of unstable library feature +extern crate arena; //~ ERROR: use of unstable library feature +extern crate collections; //~ ERROR: use of unstable library feature +extern crate core; //~ ERROR: use of unstable library feature +extern crate flate; //~ ERROR: use of unstable library feature +extern crate fmt_macros; //~ ERROR: use of unstable library feature +extern crate getopts; //~ ERROR: use of unstable library feature +extern crate graphviz; //~ ERROR: use of unstable library feature +extern crate libc; //~ ERROR: use of unstable library feature +extern crate log; //~ ERROR: use of unstable library feature +extern crate rand; //~ ERROR: use of unstable library feature +extern crate rbml; //~ ERROR: use of unstable library feature +extern crate rustc; //~ ERROR: use of unstable library feature +extern crate rustc_driver; //~ ERROR: use of unstable library feature +extern crate rustc_serialize; //~ ERROR: use of unstable library feature +extern crate rustdoc; //~ ERROR: use of unstable library feature +extern crate syntax; //~ ERROR: use of unstable library feature +extern crate term; //~ ERROR: use of unstable library feature +extern crate test; //~ ERROR: use of unstable library feature + +mod foo { + extern crate std; +} + +fn main() {} diff --git a/src/test/run-pass/derive-no-std.rs b/src/test/run-pass/derive-no-std.rs index 0234d7b0b6376..acf38184df9df 100644 --- a/src/test/run-pass/derive-no-std.rs +++ b/src/test/run-pass/derive-no-std.rs @@ -13,7 +13,7 @@ extern crate core; extern crate rand; -extern crate serialize as rustc_serialize; +extern crate rustc_serialize; extern crate collections; // Issue #16803 diff --git a/src/test/run-pass/deriving-encodable-decodable-box.rs b/src/test/run-pass/deriving-encodable-decodable-box.rs index db5a1f3f000a8..c5a9ea2b409af 100644 --- a/src/test/run-pass/deriving-encodable-decodable-box.rs +++ b/src/test/run-pass/deriving-encodable-decodable-box.rs @@ -13,12 +13,12 @@ #![feature(box_syntax)] #![feature(rustc_private)] -extern crate serialize; +extern crate rustc_serialize; -use serialize::{Encodable, Decodable}; -use serialize::json; +use rustc_serialize::{Encodable, Decodable}; +use rustc_serialize::json; -#[derive(Encodable, Decodable)] +#[derive(RustcEncodable, RustcDecodable)] struct A { foo: Box<[bool]>, } diff --git a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs b/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs index 7cc59edfcab0e..b4979bf581aad 100644 --- a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs +++ b/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs @@ -14,18 +14,18 @@ #![feature(rustc_private)] -extern crate serialize; +extern crate rustc_serialize; use std::cell::{Cell, RefCell}; -use serialize::{Encodable, Decodable}; -use serialize::json; +use rustc_serialize::{Encodable, Decodable}; +use rustc_serialize::json; -#[derive(Encodable, Decodable)] +#[derive(RustcEncodable, RustcDecodable)] struct A { baz: isize } -#[derive(Encodable, Decodable)] +#[derive(RustcEncodable, RustcDecodable)] struct B { foo: Cell, bar: RefCell, diff --git a/src/test/run-pass/deriving-global.rs b/src/test/run-pass/deriving-global.rs index 10e8ddc41f3f9..29f2ff38065b4 100644 --- a/src/test/run-pass/deriving-global.rs +++ b/src/test/run-pass/deriving-global.rs @@ -10,7 +10,7 @@ #![feature(rand, rustc_private)] -extern crate serialize; +extern crate rustc_serialize; mod submod { // if any of these are implemented without global calls for any @@ -20,21 +20,21 @@ mod submod { Hash, Clone, Debug, - Encodable, Decodable)] + RustcEncodable, RustcDecodable)] enum A { A1(usize), A2(isize) } #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, - Encodable, Decodable)] + RustcEncodable, RustcDecodable)] struct B { x: usize, y: isize } #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, - Encodable, Decodable)] + RustcEncodable, RustcDecodable)] struct C(usize, isize); } diff --git a/src/test/run-pass/extern-mod-syntax.rs b/src/test/run-pass/extern-mod-syntax.rs index 37404ee7e696c..8bfc8f8050b14 100644 --- a/src/test/run-pass/extern-mod-syntax.rs +++ b/src/test/run-pass/extern-mod-syntax.rs @@ -11,8 +11,8 @@ #![allow(unused_imports)] #![feature(rustc_private)] -extern crate serialize; -use serialize::json::Object; +extern crate rustc_serialize; +use rustc_serialize::json::Object; pub fn main() { println!("Hello world!"); diff --git a/src/test/run-pass/getopts_ref.rs b/src/test/run-pass/getopts_ref.rs index c9595d09e21b2..0a918fd7394da 100644 --- a/src/test/run-pass/getopts_ref.rs +++ b/src/test/run-pass/getopts_ref.rs @@ -8,20 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - #![feature(rustc_private)] extern crate getopts; -use getopts::{optopt, getopts}; - -pub fn main() { - let args = Vec::new(); - let opts = vec!(optopt("b", "", "something", "SMTHNG")); +fn main() { + let args = Vec::::new(); + let mut options = getopts::Options::new(); + options.optopt("b", "", "something", "SMTHNG"); - match getopts(&args, &opts) { - Ok(ref m) => - assert!(!m.opt_present("b")), + match options.parse(&args) { + Ok(ref m) => assert!(!m.opt_present("b")), Err(ref f) => panic!("{}", *f) }; diff --git a/src/test/run-pass/issue-11881.rs b/src/test/run-pass/issue-11881.rs index 9da04f7235531..4f374ed4c448a 100644 --- a/src/test/run-pass/issue-11881.rs +++ b/src/test/run-pass/issue-11881.rs @@ -12,24 +12,24 @@ #![feature(rustc_private)] extern crate rbml; -extern crate serialize; +extern crate rustc_serialize; use std::io::Cursor; use std::io::prelude::*; use std::fmt; use std::slice; -use serialize::{Encodable, Encoder}; -use serialize::json; +use rustc_serialize::{Encodable, Encoder}; +use rustc_serialize::json; use rbml::writer; -#[derive(Encodable)] +#[derive(RustcEncodable)] struct Foo { baz: bool, } -#[derive(Encodable)] +#[derive(RustcEncodable)] struct Bar { froboz: usize, } diff --git a/src/test/run-pass/issue-14021.rs b/src/test/run-pass/issue-14021.rs index 907967d115d58..4188fedad9011 100644 --- a/src/test/run-pass/issue-14021.rs +++ b/src/test/run-pass/issue-14021.rs @@ -10,19 +10,19 @@ #![feature(rustc_private)] -extern crate serialize; +extern crate rustc_serialize; -use serialize::{Encodable, Decodable}; -use serialize::json; +use rustc_serialize::{Encodable, Decodable}; +use rustc_serialize::json; -#[derive(Encodable, Decodable, PartialEq, Debug)] +#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] struct UnitLikeStruct; pub fn main() { let obj = UnitLikeStruct; let json_str: String = json::encode(&obj).unwrap(); - let json_object = json::from_str(&json_str); + let json_object = json_str.parse(); let mut decoder = json::Decoder::new(json_object.unwrap()); let mut decoded_obj: UnitLikeStruct = Decodable::decode(&mut decoder).unwrap(); diff --git a/src/test/run-pass/issue-15924.rs b/src/test/run-pass/issue-15924.rs index 0c208773884d4..f61c56336aa99 100644 --- a/src/test/run-pass/issue-15924.rs +++ b/src/test/run-pass/issue-15924.rs @@ -12,11 +12,11 @@ #![feature(rustc_private)] -extern crate serialize; +extern crate rustc_serialize; use std::fmt; -use serialize::{Encoder, Encodable}; -use serialize::json; +use rustc_serialize::{Encoder, Encodable}; +use rustc_serialize::json; struct Foo { v: T, diff --git a/src/test/run-pass/issue-2804.rs b/src/test/run-pass/issue-2804.rs index a2b4e218a079b..c44004d2aceb4 100644 --- a/src/test/run-pass/issue-2804.rs +++ b/src/test/run-pass/issue-2804.rs @@ -12,10 +12,10 @@ #![feature(rustc_private)] extern crate collections; -extern crate serialize; +extern crate rustc_serialize; use std::collections::HashMap; -use serialize::json::{self, Json}; +use rustc_serialize::json::{self, Json}; use std::option; enum object { diff --git a/src/test/run-pass/issue-4016.rs b/src/test/run-pass/issue-4016.rs index bc3fa162e02bd..3eb1804b612e9 100644 --- a/src/test/run-pass/issue-4016.rs +++ b/src/test/run-pass/issue-4016.rs @@ -8,17 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - #![feature(rustc_private)] -extern crate serialize; +extern crate rustc_serialize; -use serialize::{json, Decodable}; +use rustc_serialize::{json, Decodable}; trait JD : Decodable {} fn exec() { - let doc = json::from_str("").unwrap(); + let doc = "".parse().unwrap(); let mut decoder = json::Decoder::new(doc); let _v: T = Decodable::decode(&mut decoder).unwrap(); panic!() diff --git a/src/test/run-pass/issue-4036.rs b/src/test/run-pass/issue-4036.rs index ae7bb8a684224..5e2760cdc685e 100644 --- a/src/test/run-pass/issue-4036.rs +++ b/src/test/run-pass/issue-4036.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - // Issue #4036: Test for an issue that arose around fixing up type inference // byproducts in vtable records. @@ -16,12 +15,12 @@ #![feature(rustc_private)] -extern crate serialize; +extern crate rustc_serialize; -use serialize::{json, Decodable}; +use rustc_serialize::{json, Decodable}; pub fn main() { - let json = json::from_str("[1]").unwrap(); + let json = "[1]".parse().unwrap(); let mut decoder = json::Decoder::new(json); let _x: Vec = Decodable::decode(&mut decoder).unwrap(); }