mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Merge remote-tracking branch 'rust-lang/master'
Conflicts: mk/tests.mk src/liballoc/arc.rs src/liballoc/boxed.rs src/liballoc/rc.rs src/libcollections/bit.rs src/libcollections/btree/map.rs src/libcollections/btree/set.rs src/libcollections/dlist.rs src/libcollections/ring_buf.rs src/libcollections/slice.rs src/libcollections/str.rs src/libcollections/string.rs src/libcollections/vec.rs src/libcollections/vec_map.rs src/libcore/any.rs src/libcore/array.rs src/libcore/borrow.rs src/libcore/error.rs src/libcore/fmt/mod.rs src/libcore/iter.rs src/libcore/marker.rs src/libcore/ops.rs src/libcore/result.rs src/libcore/slice.rs src/libcore/str/mod.rs src/libregex/lib.rs src/libregex/re.rs src/librustc/lint/builtin.rs src/libstd/collections/hash/map.rs src/libstd/collections/hash/set.rs src/libstd/sync/mpsc/mod.rs src/libstd/sync/mutex.rs src/libstd/sync/poison.rs src/libstd/sync/rwlock.rs src/libsyntax/feature_gate.rs src/libsyntax/test.rs
This commit is contained in:
commit
63fcbcf3ce
1
configure
vendored
1
configure
vendored
@ -509,7 +509,6 @@ opt optimize-tests 1 "build tests with optimizations"
|
||||
opt libcpp 1 "build with llvm with libc++ instead of libstdc++ when using clang"
|
||||
opt llvm-assertions 1 "build LLVM with assertions"
|
||||
opt debug 1 "build with extra debug fun"
|
||||
opt ratchet-bench 0 "ratchet benchmarks"
|
||||
opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
|
||||
opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds"
|
||||
opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
|
||||
|
30
mk/cfg/aarch64-linux-android.mk
Normal file
30
mk/cfg/aarch64-linux-android.mk
Normal file
@ -0,0 +1,30 @@
|
||||
# aarch64-linux-android configuration
|
||||
# CROSS_PREFIX_aarch64-linux-android-
|
||||
CC_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-gcc
|
||||
CXX_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-g++
|
||||
CPP_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-gcc -E
|
||||
AR_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-ar
|
||||
CFG_LIB_NAME_aarch64-linux-android=lib$(1).so
|
||||
CFG_STATIC_LIB_NAME_aarch64-linux-android=lib$(1).a
|
||||
CFG_LIB_GLOB_aarch64-linux-android=lib$(1)-*.so
|
||||
CFG_LIB_DSYM_GLOB_aarch64-linux-android=lib$(1)-*.dylib.dSYM
|
||||
CFG_JEMALLOC_CFLAGS_aarch64-linux-android := -D__aarch64__ -DANDROID -D__ANDROID__ $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_aarch64-linux-android := -Wall -g -fPIC -D__aarch64__ -DANDROID -D__ANDROID__ $(CFLAGS)
|
||||
CFG_GCCISH_CXXFLAGS_aarch64-linux-android := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_aarch64-linux-android := -shared -fPIC -ldl -g -lm -lsupc++
|
||||
CFG_GCCISH_DEF_FLAG_aarch64-linux-android := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_aarch64-linux-android := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_aarch64-linux-android := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_aarch64-linux-android := .android.def
|
||||
CFG_LLC_FLAGS_aarch64-linux-android :=
|
||||
CFG_INSTALL_NAME_aarch64-linux-android =
|
||||
CFG_EXE_SUFFIX_aarch64-linux-android :=
|
||||
CFG_WINDOWSY_aarch64-linux-android :=
|
||||
CFG_UNIXY_aarch64-linux-android := 1
|
||||
CFG_PATH_MUNGE_aarch64-linux-android := true
|
||||
CFG_LDPATH_aarch64-linux-android :=
|
||||
CFG_RUN_aarch64-linux-android=
|
||||
CFG_RUN_TARG_aarch64-linux-android=
|
||||
RUSTC_FLAGS_aarch64-linux-android :=
|
||||
RUSTC_CROSS_FLAGS_aarch64-linux-android :=
|
||||
CFG_GNU_TRIPLE_aarch64-linux-android := aarch64-linux-android
|
12
mk/crates.mk
12
mk/crates.mk
@ -51,7 +51,7 @@
|
||||
|
||||
TARGET_CRATES := libc std flate arena term \
|
||||
serialize getopts collections test rand \
|
||||
log regex graphviz core rbml alloc \
|
||||
log graphviz core rbml alloc \
|
||||
unicode rustc_bitflags
|
||||
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
|
||||
rustc_trans rustc_back rustc_llvm rustc_privacy
|
||||
@ -95,16 +95,15 @@ DEPS_term := std log
|
||||
DEPS_getopts := std
|
||||
DEPS_collections := core alloc unicode
|
||||
DEPS_num := std
|
||||
DEPS_test := std getopts serialize rbml term regex native:rust_test_helpers
|
||||
DEPS_test := std getopts serialize rbml term native:rust_test_helpers
|
||||
DEPS_rand := core
|
||||
DEPS_log := std regex
|
||||
DEPS_regex := std
|
||||
DEPS_log := std
|
||||
DEPS_fmt_macros = std
|
||||
|
||||
TOOL_DEPS_compiletest := test getopts
|
||||
TOOL_DEPS_rustdoc := rustdoc
|
||||
TOOL_DEPS_rustc := rustc_driver
|
||||
TOOL_DEPS_rustbook := std regex rustdoc
|
||||
TOOL_DEPS_rustbook := std rustdoc
|
||||
TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs
|
||||
TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs
|
||||
TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
|
||||
@ -130,9 +129,8 @@ DOC_CRATES := $(filter-out rustc, \
|
||||
$(filter-out rustc_driver, \
|
||||
$(filter-out rustc_privacy, \
|
||||
$(filter-out log, \
|
||||
$(filter-out regex, \
|
||||
$(filter-out getopts, \
|
||||
$(filter-out syntax, $(CRATES))))))))))))
|
||||
$(filter-out syntax, $(CRATES)))))))))))
|
||||
COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \
|
||||
rustc_typeck rustc_driver syntax rustc_privacy
|
||||
|
||||
|
2
mk/rt.mk
2
mk/rt.mk
@ -141,6 +141,8 @@ else ifeq ($(OSTYPE_$(1)), apple-ios)
|
||||
JEMALLOC_ARGS_$(1) := --disable-tls
|
||||
else ifeq ($(OSTYPE_$(1)), linux-androideabi)
|
||||
JEMALLOC_ARGS_$(1) := --disable-tls
|
||||
else ifeq ($(OSTYPE_$(1)), linux-android)
|
||||
JEMALLOC_ARGS_$(1) := --disable-tls
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
|
@ -300,7 +300,8 @@ tidy:
|
||||
| grep '^$(S)src/libbacktrace' -v \
|
||||
| grep '^$(S)src/rust-installer' -v \
|
||||
| xargs $(CFG_PYTHON) $(S)src/etc/check-binaries.py
|
||||
$(Q)$(CFG_PYTHON) $(S)src/etc/featureck.py $(S)src/
|
||||
$(Q) $(CFG_PYTHON) $(S)src/etc/errorck.py $(S)src/
|
||||
$(Q) $(CFG_PYTHON) $(S)src/etc/featureck.py $(S)src/
|
||||
|
||||
|
||||
endif
|
||||
|
@ -11,9 +11,8 @@ pub use self::Mode::*;
|
||||
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use regex::Regex;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Mode {
|
||||
CompileFail,
|
||||
RunFail,
|
||||
@ -43,9 +42,9 @@ impl FromStr for Mode {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::String for Mode {
|
||||
impl fmt::Display for Mode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt(match *self {
|
||||
fmt::Display::fmt(match *self {
|
||||
CompileFail => "compile-fail",
|
||||
RunFail => "run-fail",
|
||||
RunPass => "run-pass",
|
||||
@ -58,12 +57,6 @@ impl fmt::String for Mode {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Show for Mode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Config {
|
||||
// The library paths required for running the compiler
|
||||
@ -107,28 +100,11 @@ pub struct Config {
|
||||
pub run_ignored: bool,
|
||||
|
||||
// Only run tests that match this filter
|
||||
pub filter: Option<Regex>,
|
||||
|
||||
// Precompiled regex for finding expected errors in cfail
|
||||
pub cfail_regex: Regex,
|
||||
pub filter: Option<String>,
|
||||
|
||||
// Write out a parseable log of tests that were run
|
||||
pub logfile: Option<Path>,
|
||||
|
||||
// Write out a json file containing any metrics of the run
|
||||
pub save_metrics: Option<Path>,
|
||||
|
||||
// Write and ratchet a metrics file
|
||||
pub ratchet_metrics: Option<Path>,
|
||||
|
||||
// Percent change in metrics to consider noise
|
||||
pub ratchet_noise_percent: Option<f64>,
|
||||
|
||||
// "Shard" of the testsuite to pub run: this has the form of
|
||||
// two numbers (a,b), and causes only those tests with
|
||||
// positional order equal to a mod b to run.
|
||||
pub test_shard: Option<(uint,uint)>,
|
||||
|
||||
// A command line to prefix program execution with,
|
||||
// for running under valgrind
|
||||
pub runtool: Option<String>,
|
||||
|
@ -13,6 +13,15 @@
|
||||
#![feature(slicing_syntax, unboxed_closures)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(int_uint)]
|
||||
#![feature(test)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(std_misc)]
|
||||
#![feature(path)]
|
||||
#![feature(io)]
|
||||
#![feature(core)]
|
||||
#![feature(collections)]
|
||||
#![feature(os)]
|
||||
#![feature(unicode)]
|
||||
|
||||
#![deny(warnings)]
|
||||
|
||||
@ -21,7 +30,6 @@ extern crate getopts;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate regex;
|
||||
|
||||
use std::os;
|
||||
use std::io;
|
||||
@ -32,7 +40,6 @@ use getopts::{optopt, optflag, reqopt};
|
||||
use common::Config;
|
||||
use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen};
|
||||
use util::logv;
|
||||
use regex::Regex;
|
||||
|
||||
pub mod procsrv;
|
||||
pub mod util;
|
||||
@ -76,10 +83,6 @@ pub fn parse_config(args: Vec<String> ) -> Config {
|
||||
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"),
|
||||
optopt("", "save-metrics", "file to save metrics to", "FILE"),
|
||||
optopt("", "ratchet-metrics", "file to ratchet metrics against", "FILE"),
|
||||
optopt("", "ratchet-noise-percent",
|
||||
"percent change in metrics to consider noise", "N"),
|
||||
optflag("", "jit", "run tests under the JIT"),
|
||||
optopt("", "target", "the target to build for", "TARGET"),
|
||||
optopt("", "host", "the host to build for", "HOST"),
|
||||
@ -89,7 +92,6 @@ pub fn parse_config(args: Vec<String> ) -> Config {
|
||||
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"),
|
||||
optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite", "A.B"),
|
||||
optflag("h", "help", "show this message"));
|
||||
|
||||
assert!(!args.is_empty());
|
||||
@ -120,14 +122,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
|
||||
}
|
||||
|
||||
let filter = if !matches.free.is_empty() {
|
||||
let s = matches.free[0].as_slice();
|
||||
match regex::Regex::new(s) {
|
||||
Ok(re) => Some(re),
|
||||
Err(e) => {
|
||||
println!("failed to parse filter /{}/: {:?}", s, e);
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
Some(matches.free[0].clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -149,14 +144,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
|
||||
.as_slice()).expect("invalid mode"),
|
||||
run_ignored: matches.opt_present("ignored"),
|
||||
filter: filter,
|
||||
cfail_regex: Regex::new(errors::EXPECTED_PATTERN).unwrap(),
|
||||
logfile: matches.opt_str("logfile").map(|s| Path::new(s)),
|
||||
save_metrics: matches.opt_str("save-metrics").map(|s| Path::new(s)),
|
||||
ratchet_metrics:
|
||||
matches.opt_str("ratchet-metrics").map(|s| Path::new(s)),
|
||||
ratchet_noise_percent:
|
||||
matches.opt_str("ratchet-noise-percent")
|
||||
.and_then(|s| s.as_slice().parse::<f64>()),
|
||||
runtool: matches.opt_str("runtool"),
|
||||
host_rustcflags: matches.opt_str("host-rustcflags"),
|
||||
target_rustcflags: matches.opt_str("target-rustcflags"),
|
||||
@ -175,7 +163,6 @@ pub fn parse_config(args: Vec<String> ) -> Config {
|
||||
opt_str2(matches.opt_str("adb-test-dir")).as_slice() &&
|
||||
!opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
|
||||
lldb_python_dir: matches.opt_str("lldb-python-dir"),
|
||||
test_shard: test::opt_shard(matches.opt_str("test-shard")),
|
||||
verbose: matches.opt_present("verbose"),
|
||||
}
|
||||
}
|
||||
@ -209,10 +196,6 @@ pub fn log_config(config: &Config) {
|
||||
logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir));
|
||||
logv(c, format!("adb_device_status: {}",
|
||||
config.adb_device_status));
|
||||
match config.test_shard {
|
||||
None => logv(c, "test_shard: (all)".to_string()),
|
||||
Some((a,b)) => logv(c, format!("test_shard: {}.{}", a, b))
|
||||
}
|
||||
logv(c, format!("verbose: {}", config.verbose));
|
||||
logv(c, format!("\n"));
|
||||
}
|
||||
@ -263,6 +246,9 @@ pub fn run_tests(config: &Config) {
|
||||
// parallel (especially when we have lots and lots of child processes).
|
||||
// For context, see #8904
|
||||
io::test::raise_fd_limit();
|
||||
// Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows
|
||||
// If #11207 is resolved (adding manifest to .exe) this becomes unnecessary
|
||||
os::setenv("__COMPAT_LAYER", "RunAsInvoker");
|
||||
let res = test::run_tests_console(&opts, tests.into_iter().collect());
|
||||
match res {
|
||||
Ok(true) => {}
|
||||
@ -283,15 +269,8 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
|
||||
logfile: config.logfile.clone(),
|
||||
run_tests: true,
|
||||
run_benchmarks: true,
|
||||
ratchet_metrics: config.ratchet_metrics.clone(),
|
||||
ratchet_noise_percent: config.ratchet_noise_percent.clone(),
|
||||
save_metrics: config.save_metrics.clone(),
|
||||
test_shard: config.test_shard.clone(),
|
||||
nocapture: false,
|
||||
color: test::AutoColor,
|
||||
show_boxplot: false,
|
||||
boxplot_width: 50,
|
||||
show_all_stats: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -393,18 +372,24 @@ fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> {
|
||||
if full_version_line.as_slice().trim().len() > 0 => {
|
||||
let full_version_line = full_version_line.as_slice().trim();
|
||||
|
||||
let re = Regex::new(r"(^|[^0-9])([0-9]\.[0-9])([^0-9]|$)").unwrap();
|
||||
|
||||
match re.captures(full_version_line) {
|
||||
Some(captures) => {
|
||||
Some(captures.at(2).unwrap_or("").to_string())
|
||||
// used to be a regex "(^|[^0-9])([0-9]\.[0-9])([^0-9]|$)"
|
||||
for (pos, c) in full_version_line.char_indices() {
|
||||
if !c.is_digit(10) { continue }
|
||||
if pos + 2 >= full_version_line.len() { continue }
|
||||
if full_version_line.char_at(pos + 1) != '.' { continue }
|
||||
if !full_version_line.char_at(pos + 2).is_digit(10) { continue }
|
||||
if pos > 0 && full_version_line.char_at_reverse(pos).is_digit(10) {
|
||||
continue
|
||||
}
|
||||
None => {
|
||||
println!("Could not extract GDB version from line '{}'",
|
||||
full_version_line);
|
||||
None
|
||||
if pos + 3 < full_version_line.len() &&
|
||||
full_version_line.char_at(pos + 3).is_digit(10) {
|
||||
continue
|
||||
}
|
||||
return Some(full_version_line[pos..pos+3].to_string());
|
||||
}
|
||||
println!("Could not extract GDB version from line '{}'",
|
||||
full_version_line);
|
||||
None
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
@ -427,18 +412,26 @@ fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
|
||||
if full_version_line.as_slice().trim().len() > 0 => {
|
||||
let full_version_line = full_version_line.as_slice().trim();
|
||||
|
||||
let re = Regex::new(r"[Ll][Ll][Dd][Bb]-([0-9]+)").unwrap();
|
||||
for (pos, l) in full_version_line.char_indices() {
|
||||
if l != 'l' && l != 'L' { continue }
|
||||
if pos + 5 >= full_version_line.len() { continue }
|
||||
let l = full_version_line.char_at(pos + 1);
|
||||
if l != 'l' && l != 'L' { continue }
|
||||
let d = full_version_line.char_at(pos + 2);
|
||||
if d != 'd' && d != 'D' { continue }
|
||||
let b = full_version_line.char_at(pos + 3);
|
||||
if b != 'b' && b != 'B' { continue }
|
||||
let dash = full_version_line.char_at(pos + 4);
|
||||
if dash != '-' { continue }
|
||||
|
||||
match re.captures(full_version_line) {
|
||||
Some(captures) => {
|
||||
Some(captures.at(1).unwrap_or("").to_string())
|
||||
}
|
||||
None => {
|
||||
println!("Could not extract LLDB version from line '{}'",
|
||||
full_version_line);
|
||||
None
|
||||
}
|
||||
let vers = full_version_line[pos + 5..].chars().take_while(|c| {
|
||||
c.is_digit(10)
|
||||
}).collect::<String>();
|
||||
if vers.len() > 0 { return Some(vers) }
|
||||
}
|
||||
println!("Could not extract LLDB version from line '{}'",
|
||||
full_version_line);
|
||||
None
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
|
@ -9,9 +9,7 @@
|
||||
// except according to those terms.
|
||||
use self::WhichLine::*;
|
||||
|
||||
use std::ascii::AsciiExt;
|
||||
use std::io::{BufferedReader, File};
|
||||
use regex::Regex;
|
||||
|
||||
pub struct ExpectedError {
|
||||
pub line: uint,
|
||||
@ -19,6 +17,9 @@ pub struct ExpectedError {
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Show)]
|
||||
enum WhichLine { ThisLine, FollowPrevious(uint), AdjustBackward(uint) }
|
||||
|
||||
/// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE"
|
||||
/// The former is a "follow" that inherits its target from the preceding line;
|
||||
/// the latter is an "adjusts" that goes that many lines up.
|
||||
@ -26,15 +27,8 @@ pub struct ExpectedError {
|
||||
/// Goal is to enable tests both like: //~^^^ ERROR go up three
|
||||
/// and also //~^ ERROR message one for the preceding line, and
|
||||
/// //~| ERROR message two for that same line.
|
||||
|
||||
pub static EXPECTED_PATTERN : &'static str =
|
||||
r"//~(?P<follow>\|)?(?P<adjusts>\^*)\s*(?P<kind>\S*)\s*(?P<msg>.*)";
|
||||
|
||||
#[derive(PartialEq, Show)]
|
||||
enum WhichLine { ThisLine, FollowPrevious(uint), AdjustBackward(uint) }
|
||||
|
||||
// Load any test directives embedded in the file
|
||||
pub fn load_errors(re: &Regex, testfile: &Path) -> Vec<ExpectedError> {
|
||||
pub fn load_errors(testfile: &Path) -> Vec<ExpectedError> {
|
||||
let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
|
||||
|
||||
// `last_nonfollow_error` tracks the most recently seen
|
||||
@ -50,7 +44,7 @@ pub fn load_errors(re: &Regex, testfile: &Path) -> Vec<ExpectedError> {
|
||||
rdr.lines().enumerate().filter_map(|(line_no, ln)| {
|
||||
parse_expected(last_nonfollow_error,
|
||||
line_no + 1,
|
||||
ln.unwrap().as_slice(), re)
|
||||
ln.unwrap().as_slice())
|
||||
.map(|(which, error)| {
|
||||
match which {
|
||||
FollowPrevious(_) => {}
|
||||
@ -63,30 +57,39 @@ pub fn load_errors(re: &Regex, testfile: &Path) -> Vec<ExpectedError> {
|
||||
|
||||
fn parse_expected(last_nonfollow_error: Option<uint>,
|
||||
line_num: uint,
|
||||
line: &str,
|
||||
re: &Regex) -> Option<(WhichLine, ExpectedError)> {
|
||||
re.captures(line).and_then(|caps| {
|
||||
let adjusts = caps.name("adjusts").unwrap_or("").len();
|
||||
let kind = caps.name("kind").unwrap_or("").to_ascii_lowercase();
|
||||
let msg = caps.name("msg").unwrap_or("").trim().to_string();
|
||||
let follow = caps.name("follow").unwrap_or("").len() > 0;
|
||||
line: &str) -> Option<(WhichLine, ExpectedError)> {
|
||||
let start = match line.find_str("//~") { Some(i) => i, None => return None };
|
||||
let (follow, adjusts) = if line.char_at(start + 3) == '|' {
|
||||
(true, 0)
|
||||
} else {
|
||||
(false, line[start + 3..].chars().take_while(|c| *c == '^').count())
|
||||
};
|
||||
let kind_start = start + 3 + adjusts + (follow as usize);
|
||||
let letters = line[kind_start..].chars();
|
||||
let kind = letters.skip_while(|c| c.is_whitespace())
|
||||
.take_while(|c| !c.is_whitespace())
|
||||
.map(|c| c.to_lowercase())
|
||||
.collect::<String>();
|
||||
let letters = line[kind_start..].chars();
|
||||
let msg = letters.skip_while(|c| c.is_whitespace())
|
||||
.skip_while(|c| !c.is_whitespace())
|
||||
.collect::<String>().trim().to_string();
|
||||
|
||||
let (which, line) = if follow {
|
||||
assert!(adjusts == 0, "use either //~| or //~^, not both.");
|
||||
let line = last_nonfollow_error.unwrap_or_else(|| {
|
||||
panic!("encountered //~| without preceding //~^ line.")
|
||||
});
|
||||
(FollowPrevious(line), line)
|
||||
} else {
|
||||
let which =
|
||||
if adjusts > 0 { AdjustBackward(adjusts) } else { ThisLine };
|
||||
let line = line_num - adjusts;
|
||||
(which, line)
|
||||
};
|
||||
let (which, line) = if follow {
|
||||
assert!(adjusts == 0, "use either //~| or //~^, not both.");
|
||||
let line = last_nonfollow_error.unwrap_or_else(|| {
|
||||
panic!("encountered //~| without preceding //~^ line.")
|
||||
});
|
||||
(FollowPrevious(line), line)
|
||||
} else {
|
||||
let which =
|
||||
if adjusts > 0 { AdjustBackward(adjusts) } else { ThisLine };
|
||||
let line = line_num - adjusts;
|
||||
(which, line)
|
||||
};
|
||||
|
||||
debug!("line={} which={:?} kind={:?} msg={:?}", line_num, which, kind, msg);
|
||||
Some((which, ExpectedError { line: line,
|
||||
kind: kind,
|
||||
msg: msg, }))
|
||||
})
|
||||
debug!("line={} which={:?} kind={:?} msg={:?}", line_num, which, kind, msg);
|
||||
Some((which, ExpectedError { line: line,
|
||||
kind: kind,
|
||||
msg: msg, }))
|
||||
}
|
||||
|
@ -332,8 +332,7 @@ pub fn parse_name_value_directive(line: &str, directive: &str)
|
||||
let keycolon = format!("{}:", directive);
|
||||
match line.find_str(keycolon.as_slice()) {
|
||||
Some(colon) => {
|
||||
let value = line.slice(colon + keycolon.len(),
|
||||
line.len()).to_string();
|
||||
let value = line[(colon + keycolon.len()) .. line.len()].to_string();
|
||||
debug!("{}: {}", directive, value);
|
||||
Some(value)
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
}
|
||||
|
||||
let output_to_check = get_output(props, &proc_res);
|
||||
let expected_errors = errors::load_errors(&config.cfail_regex, testfile);
|
||||
let expected_errors = errors::load_errors(testfile);
|
||||
if !expected_errors.is_empty() {
|
||||
if !props.error_patterns.is_empty() {
|
||||
fatal("both error pattern and expected errors specified");
|
||||
@ -294,6 +294,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut args = vec!("-".to_string(),
|
||||
"-Zunstable-options".to_string(),
|
||||
"--pretty".to_string(),
|
||||
pretty_type,
|
||||
format!("--target={}", config.target),
|
||||
@ -340,7 +341,7 @@ actual:\n\
|
||||
};
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut args = vec!("-".to_string(),
|
||||
"--no-trans".to_string(),
|
||||
"-Zno-trans".to_string(),
|
||||
"--crate-type=lib".to_string(),
|
||||
format!("--target={}", target),
|
||||
"-L".to_string(),
|
||||
@ -547,7 +548,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
|
||||
// Add line breakpoints
|
||||
for line in breakpoint_lines.iter() {
|
||||
script_str.push_str(&format!("break '{:?}':{}\n",
|
||||
script_str.push_str(&format!("break '{}':{}\n",
|
||||
testfile.filename_display(),
|
||||
*line)[]);
|
||||
}
|
||||
@ -750,7 +751,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
|
||||
status: status,
|
||||
stdout: out,
|
||||
stderr: err,
|
||||
cmdline: format!("{}", cmd)
|
||||
cmdline: format!("{:?}", cmd)
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -862,7 +863,7 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String])
|
||||
break;
|
||||
}
|
||||
Some(i) => {
|
||||
rest = rest.slice_from(i + frag.len());
|
||||
rest = &rest[(i + frag.len())..];
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
@ -953,7 +954,7 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
|
||||
}
|
||||
|
||||
let prefixes = expected_errors.iter().map(|ee| {
|
||||
format!("{:?}:{}:", testfile.display(), ee.line)
|
||||
format!("{}:{}:", testfile.display(), ee.line)
|
||||
}).collect::<Vec<String> >();
|
||||
|
||||
#[cfg(windows)]
|
||||
@ -1045,7 +1046,7 @@ fn scan_until_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
|
||||
if *idx >= haystack.len() {
|
||||
return false;
|
||||
}
|
||||
let opt = haystack.slice_from(*idx).find(needle);
|
||||
let opt = haystack[(*idx)..].find(needle);
|
||||
if opt.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
@ -480,14 +480,12 @@ use std::sync::{Arc,Mutex};
|
||||
fn main() {
|
||||
let numbers = Arc::new(Mutex::new(vec![1is, 2, 3]));
|
||||
|
||||
for i in 0..3 {
|
||||
for i in 0us..3 {
|
||||
let number = numbers.clone();
|
||||
Thread::spawn(move || {
|
||||
let mut array = number.lock().unwrap();
|
||||
|
||||
(*array)[i] += 1;
|
||||
|
||||
println!("numbers[{}] is {}", i, (*array)[i]);
|
||||
array[i] += 1;
|
||||
println!("numbers[{}] is {}", i, array[i]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -739,6 +739,15 @@ Rust syntax is restricted in two ways:
|
||||
* `concat!` : concatenates a comma-separated list of literals
|
||||
* `concat_idents!` : create a new identifier by concatenating the arguments
|
||||
|
||||
The following attributes are used for quasiquoting in procedural macros:
|
||||
|
||||
* `quote_expr!`
|
||||
* `quote_item!`
|
||||
* `quote_pat!`
|
||||
* `quote_stmt!`
|
||||
* `quote_tokens!`
|
||||
* `quote_ty!`
|
||||
|
||||
# Crates and source files
|
||||
|
||||
Rust is a *compiled* language. Its semantics obey a *phase distinction*
|
||||
@ -803,8 +812,9 @@ Crates contain [items](#items), each of which may have some number of
|
||||
## Items
|
||||
|
||||
```{.ebnf .gram}
|
||||
item : mod_item | fn_item | type_item | struct_item | enum_item
|
||||
| static_item | trait_item | impl_item | extern_block ;
|
||||
item : extern_crate_decl | use_decl | mod_item | fn_item | type_item
|
||||
| struct_item | enum_item | static_item | trait_item | impl_item
|
||||
| extern_block ;
|
||||
```
|
||||
|
||||
An _item_ is a component of a crate; some module items can be defined in crate
|
||||
@ -818,6 +828,8 @@ execution, and may reside in read-only memory.
|
||||
|
||||
There are several kinds of item:
|
||||
|
||||
* [`extern crate` declarations](#extern-crate-declarations)
|
||||
* [`use` declarations](#use-declarations)
|
||||
* [modules](#modules)
|
||||
* [functions](#functions)
|
||||
* [type definitions](#type-definitions)
|
||||
@ -854,13 +866,10 @@ no notion of type abstraction: there are no first-class "forall" types.
|
||||
|
||||
```{.ebnf .gram}
|
||||
mod_item : "mod" ident ( ';' | '{' mod '}' );
|
||||
mod : [ view_item | item ] * ;
|
||||
mod : item * ;
|
||||
```
|
||||
|
||||
A module is a container for zero or more [view items](#view-items) and zero or
|
||||
more [items](#items). The view items manage the visibility of the items defined
|
||||
within the module, as well as the visibility of names from outside the module
|
||||
when referenced from inside the module.
|
||||
A module is a container for zero or more [items](#items).
|
||||
|
||||
A _module item_ is a module, surrounded in braces, named, and prefixed with the
|
||||
keyword `mod`. A module item introduces a new, named module into the tree of
|
||||
@ -918,19 +927,6 @@ mod thread {
|
||||
}
|
||||
```
|
||||
|
||||
#### View items
|
||||
|
||||
```{.ebnf .gram}
|
||||
view_item : extern_crate_decl | use_decl ;
|
||||
```
|
||||
|
||||
A view item manages the namespace of a module. View items do not define new
|
||||
items, but rather, simply change other items' visibility. There are two
|
||||
kinds of view items:
|
||||
|
||||
* [`extern crate` declarations](#extern-crate-declarations)
|
||||
* [`use` declarations](#use-declarations)
|
||||
|
||||
##### Extern crate declarations
|
||||
|
||||
```{.ebnf .gram}
|
||||
@ -2041,6 +2037,9 @@ type int8_t = i8;
|
||||
item](#language-items) for more details.
|
||||
- `test` - indicates that this function is a test function, to only be compiled
|
||||
in case of `--test`.
|
||||
- `should_fail` - indicates that this test function should panic, inverting the success condition.
|
||||
- `cold` - The function is unlikely to be executed, so optimize it (and calls
|
||||
to it) differently.
|
||||
|
||||
### Static-only attributes
|
||||
|
||||
@ -2377,10 +2376,6 @@ These types help drive the compiler's analysis
|
||||
: ___Needs filling in___
|
||||
* `no_copy_bound`
|
||||
: This type does not implement "copy", even if eligible.
|
||||
* `no_send_bound`
|
||||
: This type does not implement "send", even if eligible.
|
||||
* `no_sync_bound`
|
||||
: This type does not implement "sync", even if eligible.
|
||||
* `eh_personality`
|
||||
: ___Needs filling in___
|
||||
* `exchange_free`
|
||||
@ -2820,13 +2815,12 @@ Point3d {y: 0, z: 10, .. base};
|
||||
### Block expressions
|
||||
|
||||
```{.ebnf .gram}
|
||||
block_expr : '{' [ view_item ] *
|
||||
[ stmt ';' | item ] *
|
||||
block_expr : '{' [ stmt ';' | item ] *
|
||||
[ expr ] '}' ;
|
||||
```
|
||||
|
||||
A _block expression_ is similar to a module in terms of the declarations that
|
||||
are possible. Each block conceptually introduces a new namespace scope. View
|
||||
are possible. Each block conceptually introduces a new namespace scope. Use
|
||||
items can bring new names into scopes and declared items are in scope for only
|
||||
the block itself.
|
||||
|
||||
@ -3082,18 +3076,17 @@ The precedence of Rust binary operators is ordered as follows, going from
|
||||
strong to weak:
|
||||
|
||||
```{.text .precedence}
|
||||
* / %
|
||||
as
|
||||
* / %
|
||||
+ -
|
||||
<< >>
|
||||
&
|
||||
^
|
||||
|
|
||||
< > <= >=
|
||||
== !=
|
||||
== != < > <= >=
|
||||
&&
|
||||
||
|
||||
=
|
||||
= ..
|
||||
```
|
||||
|
||||
Operators at the same precedence level are evaluated left-to-right. [Unary
|
||||
|
@ -1,296 +1,3 @@
|
||||
% Rust Documentation
|
||||
|
||||
`rustdoc` is the built-in tool for generating documentation. It integrates
|
||||
with the compiler to provide accurate hyperlinking between usage of types and
|
||||
their documentation. Furthermore, by not using a separate parser, it will
|
||||
never reject your valid Rust code.
|
||||
|
||||
# Creating Documentation
|
||||
|
||||
Documenting Rust APIs is quite simple. To document a given item, we have "doc
|
||||
comments":
|
||||
|
||||
~~~
|
||||
# #![allow(unused_attribute)]
|
||||
// the "link" crate attribute is currently required for rustdoc, but normally
|
||||
// isn't needed.
|
||||
#![crate_id = "universe"]
|
||||
#![crate_type="lib"]
|
||||
|
||||
//! Tools for dealing with universes (this is a doc comment, and is shown on
|
||||
//! the crate index page. The ! makes it apply to the parent of the comment,
|
||||
//! rather than what follows).
|
||||
|
||||
# mod workaround_the_outer_function_rustdoc_inserts {
|
||||
/// Widgets are very common (this is a doc comment, and will show up on
|
||||
/// Widget's documentation).
|
||||
pub struct Widget {
|
||||
/// All widgets have a purpose (this is a doc comment, and will show up
|
||||
/// the field's documentation).
|
||||
purpose: String,
|
||||
/// Humans are not allowed to understand some widgets
|
||||
understandable: bool
|
||||
}
|
||||
|
||||
pub fn recalibrate() {
|
||||
//! Recalibrate a pesky universe (this is also a doc comment, like above,
|
||||
//! the documentation will be applied to the *parent* item, so
|
||||
//! `recalibrate`).
|
||||
/* ... */
|
||||
}
|
||||
# }
|
||||
~~~
|
||||
|
||||
Documentation can also be controlled via the `doc` attribute on items. This is
|
||||
implicitly done by the compiler when using the above form of doc comments
|
||||
(converting the slash-based comments to `#[doc]` attributes).
|
||||
|
||||
~~~
|
||||
#[doc = "
|
||||
Calculates the factorial of a number.
|
||||
|
||||
Given the input integer `n`, this function will calculate `n!` and return it.
|
||||
"]
|
||||
pub fn factorial(n: int) -> int { if n < 2 {1} else {n * factorial(n - 1)} }
|
||||
# fn main() {}
|
||||
~~~
|
||||
|
||||
The `doc` attribute can also be used to control how rustdoc emits documentation
|
||||
in some cases.
|
||||
|
||||
```
|
||||
// Rustdoc will inline documentation of a `pub use` into this crate when the
|
||||
// `pub use` reaches across crates, but this behavior can also be disabled.
|
||||
#[doc(no_inline)]
|
||||
pub use std::option::Option;
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
Doc comments are markdown, and are currently parsed with the
|
||||
[hoedown][hoedown] library. rustdoc does not yet do any fanciness such as
|
||||
referencing other items inline, like javadoc's `@see`. One exception to this
|
||||
is that the first paragraph will be used as the "summary" of an item in the
|
||||
generated documentation:
|
||||
|
||||
~~~
|
||||
/// A whizbang. Does stuff. (this line is the summary)
|
||||
///
|
||||
/// Whizbangs are ...
|
||||
struct Whizbang;
|
||||
~~~
|
||||
|
||||
To generate the docs, run `rustdoc universe.rs`. By default, it generates a
|
||||
directory called `doc`, with the documentation for `universe` being in
|
||||
`doc/universe/index.html`. If you are using other crates with `extern crate`,
|
||||
rustdoc will even link to them when you use their types, as long as their
|
||||
documentation has already been generated by a previous run of rustdoc, or the
|
||||
crate advertises that its documentation is hosted at a given URL.
|
||||
|
||||
The generated output can be controlled with the `doc` crate attribute, which
|
||||
is how the above advertisement works. An example from the `libstd`
|
||||
documentation:
|
||||
|
||||
~~~
|
||||
#[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/")];
|
||||
~~~
|
||||
|
||||
The `html_root_url` is the prefix that rustdoc will apply to any references to
|
||||
that crate's types etc.
|
||||
|
||||
rustdoc can also generate JSON, for consumption by other tools, with
|
||||
`rustdoc --output-format json`, and also consume already-generated JSON with
|
||||
`rustdoc --input-format json`.
|
||||
|
||||
rustdoc also supports personalizing the output from crates' documentation,
|
||||
similar to markdown options.
|
||||
|
||||
- `--html-in-header FILE`: includes the contents of `FILE` at the
|
||||
end of the `<head>...</head>` section.
|
||||
- `--html-before-content FILE`: includes the contents of `FILE`
|
||||
directly after `<body>`, before the rendered content (including the
|
||||
search bar).
|
||||
- `--html-after-content FILE`: includes the contents of `FILE`
|
||||
after all the rendered content.
|
||||
|
||||
# Using the Documentation
|
||||
|
||||
The web pages generated by rustdoc present the same logical hierarchy that one
|
||||
writes a library with. Every kind of item (function, struct, etc) has its own
|
||||
color, and one can always click on a colored type to jump to its
|
||||
documentation. There is a search bar at the top, which is powered by some
|
||||
JavaScript and a statically-generated search index. No special web server is
|
||||
required for the search.
|
||||
|
||||
[hoedown]: https://github.com/hoedown/hoedown
|
||||
|
||||
# Testing the Documentation
|
||||
|
||||
`rustdoc` has support for testing code examples which appear in the
|
||||
documentation. This is helpful for keeping code examples up to date with the
|
||||
source code.
|
||||
|
||||
To test documentation, the `--test` argument is passed to rustdoc:
|
||||
|
||||
~~~ {.sh}
|
||||
rustdoc --test crate.rs
|
||||
~~~
|
||||
|
||||
## Defining tests
|
||||
|
||||
Rust documentation currently uses the markdown format, and rustdoc treats all
|
||||
code blocks as testable-by-default unless they carry a language tag of another
|
||||
language. In order to not run a test over a block of code, the `ignore` string
|
||||
can be added to the three-backtick form of markdown code block.
|
||||
|
||||
~~~md
|
||||
```
|
||||
// This is a testable code block
|
||||
```
|
||||
|
||||
```rust{.example}
|
||||
// This is rust and also testable
|
||||
```
|
||||
|
||||
```ignore
|
||||
// This is not a testable code block
|
||||
```
|
||||
|
||||
// This is a testable code block (4-space indent)
|
||||
|
||||
```sh
|
||||
# this is shell code and not tested
|
||||
```
|
||||
~~~
|
||||
|
||||
You can specify that the test's execution should fail with the `should_fail`
|
||||
directive.
|
||||
|
||||
~~~md
|
||||
```should_fail
|
||||
// This code block is expected to generate a panic when run
|
||||
```
|
||||
~~~
|
||||
|
||||
You can specify that the code block should be compiled but not run with the
|
||||
`no_run` directive.
|
||||
|
||||
~~~md
|
||||
```no_run
|
||||
// This code will be compiled but not executed
|
||||
```
|
||||
~~~
|
||||
|
||||
Lastly, you can specify that a code block be compiled as if `--test`
|
||||
were passed to the compiler using the `test_harness` directive.
|
||||
|
||||
~~~md
|
||||
```test_harness
|
||||
#[test]
|
||||
fn foo() {
|
||||
panic!("oops! (will run & register as a failed test)")
|
||||
}
|
||||
```
|
||||
~~~
|
||||
|
||||
Rustdoc also supplies some extra sugar for helping with some tedious
|
||||
documentation examples. If a line is prefixed with `# `, then the line
|
||||
will not show up in the HTML documentation, but it will be used when
|
||||
testing the code block (NB. the space after the `#` is required, so
|
||||
that one can still write things like `#[derive(Eq)]`).
|
||||
|
||||
~~~md
|
||||
```
|
||||
# /!\ The three following lines are comments, which are usually stripped off by
|
||||
# the doc-generating tool. In order to display them anyway in this particular
|
||||
# case, the character following the leading '#' is not a usual space like in
|
||||
# these first five lines but a non breakable one.
|
||||
# // showing 'fib' in this documentation would just be tedious and detracts from
|
||||
# // what's actually being documented.
|
||||
# fn fib(n: int) { n + 2 }
|
||||
|
||||
spawn(move || { fib(200); })
|
||||
```
|
||||
~~~
|
||||
|
||||
The documentation online would look like `spawn(move || { fib(200); })`, but when
|
||||
testing this code, the `fib` function will be included (so it can compile).
|
||||
|
||||
Rustdoc will automatically add a `main()` wrapper around your code, and in the right
|
||||
place. For example:
|
||||
|
||||
```
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
/// ```
|
||||
# fn foo() {}
|
||||
```
|
||||
|
||||
This will end up testing:
|
||||
|
||||
```
|
||||
fn main() {
|
||||
use std::rc::Rc;
|
||||
let five = Rc::new(5);
|
||||
}
|
||||
```
|
||||
|
||||
Here's the full algorithm:
|
||||
|
||||
1. Given a code block, if it does not contain `fn main`, it is wrapped in `fn main() { your_code }`
|
||||
2. Given that result, if it contains no `extern crate` directives but it also
|
||||
contains the name of the crate being tested, then `extern crate <name>` is
|
||||
injected at the top.
|
||||
3. Some common `allow` attributes are added for documentation examples at the top.
|
||||
|
||||
## Running tests (advanced)
|
||||
|
||||
Running tests often requires some special configuration to filter tests, find
|
||||
libraries, or try running ignored examples. The testing framework that rustdoc
|
||||
uses is built on crate `test`, which is also used when you compile crates with
|
||||
rustc's `--test` flag. Extra arguments can be passed to rustdoc's test harness
|
||||
with the `--test-args` flag.
|
||||
|
||||
~~~console
|
||||
# Only run tests containing 'foo' in their name
|
||||
$ rustdoc --test lib.rs --test-args 'foo'
|
||||
|
||||
# See what's possible when running tests
|
||||
$ rustdoc --test lib.rs --test-args '--help'
|
||||
~~~
|
||||
|
||||
When testing a library, code examples will often show how functions are used,
|
||||
and this code often requires `use`-ing paths from the crate. To accommodate this,
|
||||
rustdoc will implicitly add `extern crate <crate>;` where `<crate>` is the name of
|
||||
the crate being tested to the top of each code example. This means that rustdoc
|
||||
must be able to find a compiled version of the library crate being tested. Extra
|
||||
search paths may be added via the `-L` flag to `rustdoc`.
|
||||
|
||||
# Standalone Markdown files
|
||||
|
||||
As well as Rust crates, rustdoc supports rendering pure Markdown files
|
||||
into HTML and testing the code snippets from them. A Markdown file is
|
||||
detected by a `.md` or `.markdown` extension.
|
||||
|
||||
There are 4 options to modify the output that Rustdoc creates.
|
||||
|
||||
- `--markdown-css PATH`: adds a `<link rel="stylesheet">` tag pointing to `PATH`.
|
||||
- `--html-in-header FILE`: includes the contents of `FILE` at the
|
||||
end of the `<head>...</head>` section.
|
||||
- `--html-before-content FILE`: includes the contents of `FILE`
|
||||
directly after `<body>`, before the rendered content (including the
|
||||
title).
|
||||
- `--html-after-content FILE`: includes the contents of `FILE`
|
||||
directly before `</body>`, after all the rendered content.
|
||||
|
||||
All of these can be specified multiple times, and they are output in
|
||||
the order in which they are specified. The first line of the file being rendered must
|
||||
be the title, prefixed with `%` (e.g. this page has `% Rust
|
||||
Documentation` on the first line).
|
||||
|
||||
Like with a Rust crate, the `--test` argument will run the code
|
||||
examples to check they compile, and obeys any `--test-args` flags. The
|
||||
tests are named after the last `#` heading.
|
||||
This has been moved [into the book](book/documentation.html).
|
||||
|
@ -16,6 +16,7 @@
|
||||
* [Standard Input](standard-input.md)
|
||||
* [Guessing Game](guessing-game.md)
|
||||
* [II: Intermediate Rust](intermediate.md)
|
||||
* [More Strings](more-strings.md)
|
||||
* [Crates and Modules](crates-and-modules.md)
|
||||
* [Testing](testing.md)
|
||||
* [Pointers](pointers.md)
|
||||
@ -28,6 +29,7 @@
|
||||
* [Traits](traits.md)
|
||||
* [Threads](threads.md)
|
||||
* [Error Handling](error-handling.md)
|
||||
* [Documentation](documentation.md)
|
||||
* [III: Advanced Topics](advanced.md)
|
||||
* [FFI](ffi.md)
|
||||
* [Unsafe Code](unsafe.md)
|
||||
|
@ -117,14 +117,7 @@ fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
|
||||
arguments. `x` is an `i32`, we've done that a ton of times. `f` is a function,
|
||||
though, and that function takes an `i32` and returns an `i32`. This is
|
||||
what the requirement `Fn(i32) -> i32` for the type parameter `F` says.
|
||||
You might ask yourself: why do we need to introduce a type parameter here?
|
||||
That is because in Rust each closure has its own unique type.
|
||||
So, not only do closures with different signatures have different types,
|
||||
but different closures with the *same* signature have *different* types!
|
||||
You can think of it this way: the behaviour of a closure is part of its type.
|
||||
And since we want to support many different closures that all take
|
||||
an `i32` and return an `i32` we introduced a type parameter that is able
|
||||
to represent all these closures.
|
||||
Now `F` represents *any* function that takes an `i32` and returns an `i32`.
|
||||
|
||||
This is the most complicated function signature we've seen yet! Give it a read
|
||||
a few times until you can see how it works. It takes a teeny bit of practice, and
|
||||
@ -181,6 +174,40 @@ fn main() {
|
||||
|
||||
Doing this is not particularly common, but it's useful every once in a while.
|
||||
|
||||
Before we move on, let us look at a function that accepts two closures.
|
||||
|
||||
```{rust}
|
||||
fn compose<F, G>(x: i32, f: F, g: G) -> i32
|
||||
where F: Fn(i32) -> i32, G: Fn(i32) -> i32 {
|
||||
g(f(x))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
compose(5,
|
||||
|&: n: i32| { n + 42 },
|
||||
|&: n: i32| { n * 2 }); // evaluates to 94
|
||||
}
|
||||
```
|
||||
|
||||
You might ask yourself: why do we need to introduce two type
|
||||
parameters `F` and `G` here? Evidently, both `f` and `g` have the
|
||||
same signature: `Fn(i32) -> i32`.
|
||||
|
||||
That is because in Rust each closure has its own unique type.
|
||||
So, not only do closures with different signatures have different types,
|
||||
but different closures with the *same* signature have *different*
|
||||
types, as well!
|
||||
|
||||
You can think of it this way: the behavior of a closure is part of its
|
||||
type. Therefore, using a single type parameter for both closures
|
||||
will accept the first of them, rejecting the second. The distinct
|
||||
type of the second closure does not allow it to be represented by the
|
||||
same type parameter as that of the first. We acknowledge this, and
|
||||
use two different type parameters `F` and `G`.
|
||||
|
||||
This also introduces the `where` clause, which lets us describe type
|
||||
parameters in a more flexible manner.
|
||||
|
||||
That's all you need to get the hang of closures! Closures are a little bit
|
||||
strange at first, but once you're used to them, you'll miss them
|
||||
in other languages. Passing functions to other functions is
|
||||
|
@ -257,7 +257,7 @@ fn goodbye() -> String {
|
||||
|
||||
(This is "Sayōnara", if you're curious.)
|
||||
|
||||
Now that we have our some functionality in our crate, let's try to use it from
|
||||
Now that we have some functionality in our crate, let's try to use it from
|
||||
another crate.
|
||||
|
||||
# Importing External Crates
|
||||
@ -287,8 +287,7 @@ mentioned earlier, you can use double colons to refer to sub-modules and the
|
||||
functions inside of them.
|
||||
|
||||
Also, Cargo assumes that `src/main.rs` is the crate root of a binary crate,
|
||||
rather than a library crate. Once we compile `src/main.rs`, we'll get an
|
||||
executable that we can run. Our package now has two crates: `src/lib.rs` and
|
||||
rather than a library crate. Our package now has two crates: `src/lib.rs` and
|
||||
`src/main.rs`. This pattern is quite common for executable crates: most
|
||||
functionality is in a library crate, and the executable crate uses that
|
||||
library. This way, other programs can also use the library crate, and it's also
|
||||
|
296
src/doc/trpl/documentation.md
Normal file
296
src/doc/trpl/documentation.md
Normal file
@ -0,0 +1,296 @@
|
||||
% Rust Documentation
|
||||
|
||||
`rustdoc` is the built-in tool for generating documentation. It integrates
|
||||
with the compiler to provide accurate hyperlinking between usage of types and
|
||||
their documentation. Furthermore, by not using a separate parser, it will
|
||||
never reject your valid Rust code.
|
||||
|
||||
# Creating Documentation
|
||||
|
||||
Documenting Rust APIs is quite simple. To document a given item, we have "doc
|
||||
comments":
|
||||
|
||||
~~~
|
||||
# #![allow(unused_attribute)]
|
||||
// the "link" crate attribute is currently required for rustdoc, but normally
|
||||
// isn't needed.
|
||||
#![crate_id = "universe"]
|
||||
#![crate_type="lib"]
|
||||
|
||||
//! Tools for dealing with universes (this is a doc comment, and is shown on
|
||||
//! the crate index page. The ! makes it apply to the parent of the comment,
|
||||
//! rather than what follows).
|
||||
|
||||
# mod workaround_the_outer_function_rustdoc_inserts {
|
||||
/// Widgets are very common (this is a doc comment, and will show up on
|
||||
/// Widget's documentation).
|
||||
pub struct Widget {
|
||||
/// All widgets have a purpose (this is a doc comment, and will show up
|
||||
/// the field's documentation).
|
||||
purpose: String,
|
||||
/// Humans are not allowed to understand some widgets
|
||||
understandable: bool
|
||||
}
|
||||
|
||||
pub fn recalibrate() {
|
||||
//! Recalibrate a pesky universe (this is also a doc comment, like above,
|
||||
//! the documentation will be applied to the *parent* item, so
|
||||
//! `recalibrate`).
|
||||
/* ... */
|
||||
}
|
||||
# }
|
||||
~~~
|
||||
|
||||
Documentation can also be controlled via the `doc` attribute on items. This is
|
||||
implicitly done by the compiler when using the above form of doc comments
|
||||
(converting the slash-based comments to `#[doc]` attributes).
|
||||
|
||||
~~~
|
||||
#[doc = "
|
||||
Calculates the factorial of a number.
|
||||
|
||||
Given the input integer `n`, this function will calculate `n!` and return it.
|
||||
"]
|
||||
pub fn factorial(n: int) -> int { if n < 2 {1} else {n * factorial(n - 1)} }
|
||||
# fn main() {}
|
||||
~~~
|
||||
|
||||
The `doc` attribute can also be used to control how rustdoc emits documentation
|
||||
in some cases.
|
||||
|
||||
```
|
||||
// Rustdoc will inline documentation of a `pub use` into this crate when the
|
||||
// `pub use` reaches across crates, but this behavior can also be disabled.
|
||||
#[doc(no_inline)]
|
||||
pub use std::option::Option;
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
Doc comments are markdown, and are currently parsed with the
|
||||
[hoedown][hoedown] library. rustdoc does not yet do any fanciness such as
|
||||
referencing other items inline, like javadoc's `@see`. One exception to this
|
||||
is that the first paragraph will be used as the "summary" of an item in the
|
||||
generated documentation:
|
||||
|
||||
~~~
|
||||
/// A whizbang. Does stuff. (this line is the summary)
|
||||
///
|
||||
/// Whizbangs are ...
|
||||
struct Whizbang;
|
||||
~~~
|
||||
|
||||
To generate the docs, run `rustdoc universe.rs`. By default, it generates a
|
||||
directory called `doc`, with the documentation for `universe` being in
|
||||
`doc/universe/index.html`. If you are using other crates with `extern crate`,
|
||||
rustdoc will even link to them when you use their types, as long as their
|
||||
documentation has already been generated by a previous run of rustdoc, or the
|
||||
crate advertises that its documentation is hosted at a given URL.
|
||||
|
||||
The generated output can be controlled with the `doc` crate attribute, which
|
||||
is how the above advertisement works. An example from the `libstd`
|
||||
documentation:
|
||||
|
||||
~~~
|
||||
#[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/")];
|
||||
~~~
|
||||
|
||||
The `html_root_url` is the prefix that rustdoc will apply to any references to
|
||||
that crate's types etc.
|
||||
|
||||
rustdoc can also generate JSON, for consumption by other tools, with
|
||||
`rustdoc --output-format json`, and also consume already-generated JSON with
|
||||
`rustdoc --input-format json`.
|
||||
|
||||
rustdoc also supports personalizing the output from crates' documentation,
|
||||
similar to markdown options.
|
||||
|
||||
- `--html-in-header FILE`: includes the contents of `FILE` at the
|
||||
end of the `<head>...</head>` section.
|
||||
- `--html-before-content FILE`: includes the contents of `FILE`
|
||||
directly after `<body>`, before the rendered content (including the
|
||||
search bar).
|
||||
- `--html-after-content FILE`: includes the contents of `FILE`
|
||||
after all the rendered content.
|
||||
|
||||
# Using the Documentation
|
||||
|
||||
The web pages generated by rustdoc present the same logical hierarchy that one
|
||||
writes a library with. Every kind of item (function, struct, etc) has its own
|
||||
color, and one can always click on a colored type to jump to its
|
||||
documentation. There is a search bar at the top, which is powered by some
|
||||
JavaScript and a statically-generated search index. No special web server is
|
||||
required for the search.
|
||||
|
||||
[hoedown]: https://github.com/hoedown/hoedown
|
||||
|
||||
# Testing the Documentation
|
||||
|
||||
`rustdoc` has support for testing code examples which appear in the
|
||||
documentation. This is helpful for keeping code examples up to date with the
|
||||
source code.
|
||||
|
||||
To test documentation, the `--test` argument is passed to rustdoc:
|
||||
|
||||
~~~ {.sh}
|
||||
rustdoc --test crate.rs
|
||||
~~~
|
||||
|
||||
## Defining tests
|
||||
|
||||
Rust documentation currently uses the markdown format, and rustdoc treats all
|
||||
code blocks as testable-by-default unless they carry a language tag of another
|
||||
language. In order to not run a test over a block of code, the `ignore` string
|
||||
can be added to the three-backtick form of markdown code block.
|
||||
|
||||
~~~md
|
||||
```
|
||||
// This is a testable code block
|
||||
```
|
||||
|
||||
```rust{.example}
|
||||
// This is rust and also testable
|
||||
```
|
||||
|
||||
```ignore
|
||||
// This is not a testable code block
|
||||
```
|
||||
|
||||
// This is a testable code block (4-space indent)
|
||||
|
||||
```sh
|
||||
# this is shell code and not tested
|
||||
```
|
||||
~~~
|
||||
|
||||
You can specify that the test's execution should fail with the `should_fail`
|
||||
directive.
|
||||
|
||||
~~~md
|
||||
```should_fail
|
||||
// This code block is expected to generate a panic when run
|
||||
```
|
||||
~~~
|
||||
|
||||
You can specify that the code block should be compiled but not run with the
|
||||
`no_run` directive.
|
||||
|
||||
~~~md
|
||||
```no_run
|
||||
// This code will be compiled but not executed
|
||||
```
|
||||
~~~
|
||||
|
||||
Lastly, you can specify that a code block be compiled as if `--test`
|
||||
were passed to the compiler using the `test_harness` directive.
|
||||
|
||||
~~~md
|
||||
```test_harness
|
||||
#[test]
|
||||
fn foo() {
|
||||
panic!("oops! (will run & register as a failed test)")
|
||||
}
|
||||
```
|
||||
~~~
|
||||
|
||||
Rustdoc also supplies some extra sugar for helping with some tedious
|
||||
documentation examples. If a line is prefixed with `# `, then the line
|
||||
will not show up in the HTML documentation, but it will be used when
|
||||
testing the code block (NB. the space after the `#` is required, so
|
||||
that one can still write things like `#[derive(Eq)]`).
|
||||
|
||||
~~~md
|
||||
```
|
||||
# /!\ The three following lines are comments, which are usually stripped off by
|
||||
# the doc-generating tool. In order to display them anyway in this particular
|
||||
# case, the character following the leading '#' is not a usual space like in
|
||||
# these first five lines but a non breakable one.
|
||||
# // showing 'fib' in this documentation would just be tedious and detracts from
|
||||
# // what's actually being documented.
|
||||
# fn fib(n: int) { n + 2 }
|
||||
|
||||
spawn(move || { fib(200); })
|
||||
```
|
||||
~~~
|
||||
|
||||
The documentation online would look like `spawn(move || { fib(200); })`, but when
|
||||
testing this code, the `fib` function will be included (so it can compile).
|
||||
|
||||
Rustdoc will automatically add a `main()` wrapper around your code, and in the right
|
||||
place. For example:
|
||||
|
||||
```
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
/// ```
|
||||
# fn foo() {}
|
||||
```
|
||||
|
||||
This will end up testing:
|
||||
|
||||
```
|
||||
fn main() {
|
||||
use std::rc::Rc;
|
||||
let five = Rc::new(5);
|
||||
}
|
||||
```
|
||||
|
||||
Here's the full algorithm:
|
||||
|
||||
1. Given a code block, if it does not contain `fn main`, it is wrapped in `fn main() { your_code }`
|
||||
2. Given that result, if it contains no `extern crate` directives but it also
|
||||
contains the name of the crate being tested, then `extern crate <name>` is
|
||||
injected at the top.
|
||||
3. Some common `allow` attributes are added for documentation examples at the top.
|
||||
|
||||
## Running tests (advanced)
|
||||
|
||||
Running tests often requires some special configuration to filter tests, find
|
||||
libraries, or try running ignored examples. The testing framework that rustdoc
|
||||
uses is built on crate `test`, which is also used when you compile crates with
|
||||
rustc's `--test` flag. Extra arguments can be passed to rustdoc's test harness
|
||||
with the `--test-args` flag.
|
||||
|
||||
~~~console
|
||||
# Only run tests containing 'foo' in their name
|
||||
$ rustdoc --test lib.rs --test-args 'foo'
|
||||
|
||||
# See what's possible when running tests
|
||||
$ rustdoc --test lib.rs --test-args '--help'
|
||||
~~~
|
||||
|
||||
When testing a library, code examples will often show how functions are used,
|
||||
and this code often requires `use`-ing paths from the crate. To accommodate this,
|
||||
rustdoc will implicitly add `extern crate <crate>;` where `<crate>` is the name of
|
||||
the crate being tested to the top of each code example. This means that rustdoc
|
||||
must be able to find a compiled version of the library crate being tested. Extra
|
||||
search paths may be added via the `-L` flag to `rustdoc`.
|
||||
|
||||
# Standalone Markdown files
|
||||
|
||||
As well as Rust crates, rustdoc supports rendering pure Markdown files
|
||||
into HTML and testing the code snippets from them. A Markdown file is
|
||||
detected by a `.md` or `.markdown` extension.
|
||||
|
||||
There are 4 options to modify the output that Rustdoc creates.
|
||||
|
||||
- `--markdown-css PATH`: adds a `<link rel="stylesheet">` tag pointing to `PATH`.
|
||||
- `--html-in-header FILE`: includes the contents of `FILE` at the
|
||||
end of the `<head>...</head>` section.
|
||||
- `--html-before-content FILE`: includes the contents of `FILE`
|
||||
directly after `<body>`, before the rendered content (including the
|
||||
title).
|
||||
- `--html-after-content FILE`: includes the contents of `FILE`
|
||||
directly before `</body>`, after all the rendered content.
|
||||
|
||||
All of these can be specified multiple times, and they are output in
|
||||
the order in which they are specified. The first line of the file being rendered must
|
||||
be the title, prefixed with `%` (e.g. this page has `% Rust
|
||||
Documentation` on the first line).
|
||||
|
||||
Like with a Rust crate, the `--test` argument will run the code
|
||||
examples to check they compile, and obeys any `--test-args` flags. The
|
||||
tests are named after the last `#` heading.
|
@ -1,4 +1,4 @@
|
||||
% `if`
|
||||
% If
|
||||
|
||||
Rust's take on `if` is not particularly complex, but it's much more like the
|
||||
`if` you'll find in a dynamically typed language than in a more traditional
|
||||
|
@ -123,7 +123,7 @@ We now loop forever with `loop` and use `break` to break out early.
|
||||
iteration. This will only print the odd numbers:
|
||||
|
||||
```{rust}
|
||||
for x in 0..10 {
|
||||
for x in 0u32..10 {
|
||||
if x % 2 == 0 { continue; }
|
||||
|
||||
println!("{}", x);
|
||||
|
283
src/doc/trpl/more-strings.md
Normal file
283
src/doc/trpl/more-strings.md
Normal file
@ -0,0 +1,283 @@
|
||||
% More Strings
|
||||
|
||||
Strings are an important concept to master in any programming language. If you
|
||||
come from a managed language background, you may be surprised at the complexity
|
||||
of string handling in a systems programming language. Efficient access and
|
||||
allocation of memory for a dynamically sized structure involves a lot of
|
||||
details. Luckily, Rust has lots of tools to help us here.
|
||||
|
||||
A **string** is a sequence of unicode scalar values encoded as a stream of
|
||||
UTF-8 bytes. All strings are guaranteed to be validly-encoded UTF-8 sequences.
|
||||
Additionally, strings are not null-terminated and can contain null bytes.
|
||||
|
||||
Rust has two main types of strings: `&str` and `String`.
|
||||
|
||||
# &str
|
||||
|
||||
The first kind is a `&str`. This is pronounced a 'string slice'.
|
||||
String literals are of the type `&str`:
|
||||
|
||||
```
|
||||
let string = "Hello there.";
|
||||
```
|
||||
|
||||
Like any Rust reference, string slices have an associated lifetime. A string
|
||||
literal is a `&'static str`. A string slice can be written without an explicit
|
||||
lifetime in many cases, such as in function arguments. In these cases the
|
||||
lifetime will be inferred:
|
||||
|
||||
```
|
||||
fn takes_slice(slice: &str) {
|
||||
println!("Got: {}", slice);
|
||||
}
|
||||
```
|
||||
|
||||
Like vector slices, string slices are simply a pointer plus a length. This
|
||||
means that they're a 'view' into an already-allocated string, such as a
|
||||
string literal or a `String`.
|
||||
|
||||
# String
|
||||
|
||||
A `String` is a heap-allocated string. This string is growable, and is also
|
||||
guaranteed to be UTF-8.
|
||||
|
||||
```
|
||||
let mut s = "Hello".to_string();
|
||||
println!("{}", s);
|
||||
|
||||
s.push_str(", world.");
|
||||
println!("{}", s);
|
||||
```
|
||||
|
||||
You can coerce a `String` into a `&str` by dereferencing it:
|
||||
|
||||
```
|
||||
fn takes_slice(slice: &str) {
|
||||
println!("Got: {}", slice);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "Hello".to_string();
|
||||
takes_slice(&*s);
|
||||
}
|
||||
```
|
||||
|
||||
You can also get a `&str` from a stack-allocated array of bytes:
|
||||
|
||||
```
|
||||
use std::str;
|
||||
|
||||
let x: &[u8] = &[b'a', b'b'];
|
||||
let stack_str: &str = str::from_utf8(x).unwrap();
|
||||
```
|
||||
|
||||
# Best Practices
|
||||
|
||||
## `String` vs. `&str`
|
||||
|
||||
In general, you should prefer `String` when you need ownership, and `&str` when
|
||||
you just need to borrow a string. This is very similar to using `Vec<T>` vs. `&[T]`,
|
||||
and `T` vs `&T` in general.
|
||||
|
||||
This means starting off with this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn foo(s: &str) {
|
||||
```
|
||||
|
||||
and only moving to this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn foo(s: String) {
|
||||
```
|
||||
|
||||
If you have good reason. It's not polite to hold on to ownership you don't
|
||||
need, and it can make your lifetimes more complex.
|
||||
|
||||
## Generic functions
|
||||
|
||||
To write a function that's generic over types of strings, use `&str`.
|
||||
|
||||
```
|
||||
fn some_string_length(x: &str) -> uint {
|
||||
x.len()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "Hello, world";
|
||||
|
||||
println!("{}", some_string_length(s));
|
||||
|
||||
let s = "Hello, world".to_string();
|
||||
|
||||
println!("{}", some_string_length(s.as_slice()));
|
||||
}
|
||||
```
|
||||
|
||||
Both of these lines will print `12`.
|
||||
|
||||
## Indexing strings
|
||||
|
||||
You may be tempted to try to access a certain character of a `String`, like
|
||||
this:
|
||||
|
||||
```{rust,ignore}
|
||||
let s = "hello".to_string();
|
||||
|
||||
println!("{}", s[0]);
|
||||
```
|
||||
|
||||
This does not compile. This is on purpose. In the world of UTF-8, direct
|
||||
indexing is basically never what you want to do. The reason is that each
|
||||
character can be a variable number of bytes. This means that you have to iterate
|
||||
through the characters anyway, which is an O(n) operation.
|
||||
|
||||
There's 3 basic levels of unicode (and its encodings):
|
||||
|
||||
- code units, the underlying data type used to store everything
|
||||
- code points/unicode scalar values (char)
|
||||
- graphemes (visible characters)
|
||||
|
||||
Rust provides iterators for each of these situations:
|
||||
|
||||
- `.bytes()` will iterate over the underlying bytes
|
||||
- `.chars()` will iterate over the code points
|
||||
- `.graphemes()` will iterate over each grapheme
|
||||
|
||||
Usually, the `graphemes()` method on `&str` is what you want:
|
||||
|
||||
```
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.graphemes(true) {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This prints:
|
||||
|
||||
```text
|
||||
u͔
|
||||
n͈̰̎
|
||||
i̙̮͚̦
|
||||
c͚̉
|
||||
o̼̩̰͗
|
||||
d͔̆̓ͥ
|
||||
é
|
||||
```
|
||||
|
||||
Note that `l` has the type `&str` here, since a single grapheme can consist of
|
||||
multiple codepoints, so a `char` wouldn't be appropriate.
|
||||
|
||||
This will print out each visible character in turn, as you'd expect: first "u͔", then
|
||||
"n͈̰̎", etc. If you wanted each individual codepoint of each grapheme, you can use `.chars()`:
|
||||
|
||||
```
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.chars() {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This prints:
|
||||
|
||||
```text
|
||||
u
|
||||
͔
|
||||
n
|
||||
̎
|
||||
͈
|
||||
̰
|
||||
i
|
||||
̙
|
||||
̮
|
||||
͚
|
||||
̦
|
||||
c
|
||||
̉
|
||||
͚
|
||||
o
|
||||
͗
|
||||
̼
|
||||
̩
|
||||
̰
|
||||
d
|
||||
̆
|
||||
̓
|
||||
ͥ
|
||||
͔
|
||||
e
|
||||
́
|
||||
```
|
||||
|
||||
You can see how some of them are combining characters, and therefore the output
|
||||
looks a bit odd.
|
||||
|
||||
If you want the individual byte representation of each codepoint, you can use
|
||||
`.bytes()`:
|
||||
|
||||
```
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.bytes() {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This will print:
|
||||
|
||||
```text
|
||||
117
|
||||
205
|
||||
148
|
||||
110
|
||||
204
|
||||
142
|
||||
205
|
||||
136
|
||||
204
|
||||
176
|
||||
105
|
||||
204
|
||||
153
|
||||
204
|
||||
174
|
||||
205
|
||||
154
|
||||
204
|
||||
166
|
||||
99
|
||||
204
|
||||
137
|
||||
205
|
||||
154
|
||||
111
|
||||
205
|
||||
151
|
||||
204
|
||||
188
|
||||
204
|
||||
169
|
||||
204
|
||||
176
|
||||
100
|
||||
204
|
||||
134
|
||||
205
|
||||
131
|
||||
205
|
||||
165
|
||||
205
|
||||
148
|
||||
101
|
||||
204
|
||||
129
|
||||
```
|
||||
|
||||
Many more bytes than graphemes!
|
||||
|
||||
# Other Documentation
|
||||
|
||||
* [the `&str` API documentation](std/str/index.html)
|
||||
* [the `String` API documentation](std/string/index.html)
|
@ -244,8 +244,8 @@ three. The ownership system in Rust does this through a concept called
|
||||
Remember the function that borrowed an `i32`? Let's look at it again.
|
||||
|
||||
```rust
|
||||
fn add_one(num: &i32) -> i32 {
|
||||
*num + 1
|
||||
fn add_one(num: &mut i32) {
|
||||
*num += 1;
|
||||
}
|
||||
```
|
||||
|
||||
@ -255,8 +255,8 @@ cover the others later. Without eliding the lifetimes, `add_one` looks like
|
||||
this:
|
||||
|
||||
```rust
|
||||
fn add_one<'a>(num: &'a i32) -> i32 {
|
||||
*num + 1
|
||||
fn add_one<'a>(num: &'a mut i32) {
|
||||
*num += 1;
|
||||
}
|
||||
```
|
||||
|
||||
@ -278,12 +278,12 @@ fn add_two<'a, 'b>(...)
|
||||
Then in our parameter list, we use the lifetimes we've named:
|
||||
|
||||
```{rust,ignore}
|
||||
...(num: &'a i32) -> ...
|
||||
...(num: &'a mut i32)
|
||||
```
|
||||
|
||||
If you compare `&i32` to `&'a i32`, they're the same, it's just that the
|
||||
lifetime `'a` has snuck in between the `&` and the `i32`. We read `&i32` as "a
|
||||
reference to an i32" and `&'a i32` as "a reference to an i32 with the lifetime 'a.'"
|
||||
If you compare `&mut i32` to `&'a mut i32`, they're the same, it's just that the
|
||||
lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut i32` as "a
|
||||
mutable reference to an i32" and `&'a mut i32` as "a mutable reference to an i32 with the lifetime 'a.'"
|
||||
|
||||
Why do lifetimes matter? Well, for example, here's some code:
|
||||
|
||||
|
@ -87,7 +87,7 @@ println!("{}", x + z);
|
||||
This gives us an error:
|
||||
|
||||
```text
|
||||
hello.rs:6:24: 6:25 error: mismatched types: expected `i32` but found `&i32` (expected i32 but found &-ptr)
|
||||
hello.rs:6:24: 6:25 error: mismatched types: expected `_`, found `&_` (expected integral variable, found &-ptr)
|
||||
hello.rs:6 println!("{}", x + z);
|
||||
^
|
||||
```
|
||||
@ -305,7 +305,7 @@ References are immutable by default:
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
|
||||
*y = 5; // error: cannot assign to immutable dereference of `&`-pointer `*y`
|
||||
*y = 5; // error: cannot assign to immutable borrowed content `*y`
|
||||
```
|
||||
|
||||
They can be made mutable with `mut`, but only if its referent is also mutable.
|
||||
@ -668,7 +668,7 @@ struct BigStruct {
|
||||
}
|
||||
|
||||
fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
|
||||
return Box::new(*x);
|
||||
Box::new(*x)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@ -696,7 +696,7 @@ struct BigStruct {
|
||||
}
|
||||
|
||||
fn foo(x: Box<BigStruct>) -> BigStruct {
|
||||
return *x;
|
||||
*x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -179,7 +179,7 @@ for init_val in 0 .. 3 {
|
||||
}
|
||||
|
||||
let result = rx.recv().unwrap() + rx.recv().unwrap() + rx.recv().unwrap();
|
||||
# fn some_expensive_computation(_i: u32) -> u32 { 42 }
|
||||
# fn some_expensive_computation(_i: i32) -> i32 { 42 }
|
||||
```
|
||||
|
||||
Cloning a `Sender` produces a new handle to the same channel, allowing multiple
|
||||
@ -207,7 +207,7 @@ let rxs = (0 .. 3).map(|&:init_val| {
|
||||
|
||||
// Wait on each port, accumulating the results
|
||||
let result = rxs.iter().fold(0, |&:accum, rx| accum + rx.recv().unwrap() );
|
||||
# fn some_expensive_computation(_i: u32) -> u32 { 42 }
|
||||
# fn some_expensive_computation(_i: i32) -> i32 { 42 }
|
||||
```
|
||||
|
||||
## Backgrounding computations: Futures
|
||||
|
@ -707,7 +707,7 @@ Other features provided by lang items include:
|
||||
various kinds; lang items `send`, `sync` and `copy`.
|
||||
- the marker types and variance indicators found in
|
||||
`std::marker`; lang items `covariant_type`,
|
||||
`contravariant_lifetime`, `no_sync_bound`, etc.
|
||||
`contravariant_lifetime`, etc.
|
||||
|
||||
Lang items are loaded lazily by the compiler; e.g. if one never uses
|
||||
`Box` then there is no need to define functions for `exchange_malloc`
|
||||
|
@ -54,6 +54,11 @@
|
||||
:type 'integer
|
||||
:group 'rust-mode)
|
||||
|
||||
(defcustom rust-indent-method-chain nil
|
||||
"Indent Rust method chains, aligned by the '.' operators"
|
||||
:type 'boolean
|
||||
:group 'rust-mode)
|
||||
|
||||
(defun rust-paren-level () (nth 0 (syntax-ppss)))
|
||||
(defun rust-in-str-or-cmnt () (nth 8 (syntax-ppss)))
|
||||
(defun rust-rewind-past-str-cmnt () (goto-char (nth 8 (syntax-ppss))))
|
||||
@ -73,10 +78,19 @@
|
||||
;; open bracket ends the line
|
||||
(when (not (looking-at "[[:blank:]]*\\(?://.*\\)?$"))
|
||||
(when (looking-at "[[:space:]]")
|
||||
(forward-word 1)
|
||||
(backward-word 1))
|
||||
(forward-word 1)
|
||||
(backward-word 1))
|
||||
(current-column))))
|
||||
|
||||
(defun rust-align-to-method-chain ()
|
||||
(save-excursion
|
||||
(previous-line)
|
||||
(end-of-line)
|
||||
(backward-word 1)
|
||||
(backward-char)
|
||||
(when (looking-at "\\..+\(.*\)\n")
|
||||
(- (current-column) rust-indent-offset))))
|
||||
|
||||
(defun rust-rewind-to-beginning-of-current-level-expr ()
|
||||
(let ((current-level (rust-paren-level)))
|
||||
(back-to-indentation)
|
||||
@ -99,10 +113,13 @@
|
||||
;; the inside of it correctly relative to the outside.
|
||||
(if (= 0 level)
|
||||
0
|
||||
(or
|
||||
(when rust-indent-method-chain
|
||||
(rust-align-to-method-chain))
|
||||
(save-excursion
|
||||
(backward-up-list)
|
||||
(rust-rewind-to-beginning-of-current-level-expr)
|
||||
(+ (current-column) rust-indent-offset)))))
|
||||
(+ (current-column) rust-indent-offset))))))
|
||||
(cond
|
||||
;; A function return type is indented to the corresponding function arguments
|
||||
((looking-at "->")
|
||||
@ -114,6 +131,16 @@
|
||||
;; A closing brace is 1 level unindended
|
||||
((looking-at "}") (- baseline rust-indent-offset))
|
||||
|
||||
;;Line up method chains by their .'s
|
||||
((when (and rust-indent-method-chain
|
||||
(looking-at "\..+\(.*\);?\n"))
|
||||
(or
|
||||
(let ((method-indent (rust-align-to-method-chain)))
|
||||
(when method-indent
|
||||
(+ method-indent rust-indent-offset)))
|
||||
(+ baseline rust-indent-offset))))
|
||||
|
||||
|
||||
;; Doc comments in /** style with leading * indent to line up the *s
|
||||
((and (nth 4 (syntax-ppss)) (looking-at "*"))
|
||||
(+ 1 baseline))
|
||||
|
70
src/etc/errorck.py
Normal file
70
src/etc/errorck.py
Normal file
@ -0,0 +1,70 @@
|
||||
# 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 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
# Digs error codes out of files named 'diagnostics.rs' across
|
||||
# the tree, and ensures thare are no duplicates.
|
||||
|
||||
import sys, os, re
|
||||
|
||||
src_dir = sys.argv[1]
|
||||
|
||||
errcode_map = { }
|
||||
|
||||
for (dirpath, dirnames, filenames) in os.walk(src_dir):
|
||||
|
||||
if "src/test" in dirpath or "src/llvm" in dirpath:
|
||||
# Short circuit for fast
|
||||
continue
|
||||
|
||||
for filename in filenames:
|
||||
if filename != "diagnostics.rs":
|
||||
continue
|
||||
|
||||
path = os.path.join(dirpath, filename)
|
||||
line_num = 1
|
||||
with open(path, 'r') as f:
|
||||
for line in f:
|
||||
|
||||
p = re.compile("(E\d\d\d\d)")
|
||||
m = p.search(line)
|
||||
if not m is None:
|
||||
errcode = m.group(1)
|
||||
|
||||
new_record = [(errcode, path, line_num, line)]
|
||||
existing = errcode_map.get(errcode)
|
||||
if existing is not None:
|
||||
# This is a dupe
|
||||
errcode_map[errcode] = existing + new_record
|
||||
else:
|
||||
errcode_map[errcode] = new_record
|
||||
|
||||
line_num += 1
|
||||
|
||||
errors = False
|
||||
all_errors = []
|
||||
for errcode in errcode_map:
|
||||
entries = errcode_map[errcode]
|
||||
all_errors += [entries[0][0]]
|
||||
if len(entries) > 1:
|
||||
print "error: duplicate error code " + errcode
|
||||
for entry in entries:
|
||||
print entry[1] + ": " + str(entry[2])
|
||||
print entry[3]
|
||||
errors = True
|
||||
|
||||
print str(len(errcode_map)) + " error codes"
|
||||
|
||||
all_errors.sort()
|
||||
all_errors.reverse()
|
||||
|
||||
print "highest error code: " + all_errors[0]
|
||||
|
||||
if errors:
|
||||
sys.exit(1)
|
@ -433,11 +433,16 @@ CFG_TMP_DIR=$(mktemp -d 2>/dev/null \
|
||||
|| mktemp -d -t 'rustup-tmp-install' 2>/dev/null \
|
||||
|| create_tmp_dir)
|
||||
|
||||
# If we're saving nightlies and we didn't specify which one, grab todays.
|
||||
# Otherwise we'll use the latest version.
|
||||
# If we're saving nightlies and we didn't specify which one, grab the latest
|
||||
# verison from the perspective of the server. Buildbot has typically finished
|
||||
# building and uploading by ~8UTC, but we want to include a little buffer.
|
||||
#
|
||||
# FIXME It would be better to use the known most recent nightly that has been
|
||||
# built. This is waiting on a change to have buildbot publish metadata that
|
||||
# can be queried.
|
||||
if [ -n "${CFG_SAVE}" -a -z "${CFG_DATE}" ];
|
||||
then
|
||||
CFG_DATE=`date "+%Y-%m-%d"`
|
||||
CFG_DATE=`TZ=Etc/UTC+9 date "+%Y-%m-%d"`
|
||||
fi
|
||||
|
||||
RUST_URL="https://static.rust-lang.org/dist"
|
||||
@ -453,16 +458,33 @@ then
|
||||
RUST_URL="${RUST_URL}/${CFG_DATE}"
|
||||
fi
|
||||
|
||||
verify_hash() {
|
||||
remote_sha256="$1"
|
||||
local_file="$2"
|
||||
|
||||
download_hash() {
|
||||
msg "Downloading ${remote_sha256}"
|
||||
remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"`
|
||||
if [ -n "${CFG_SAVE}" ]; then
|
||||
echo "${remote_sha256}" > "${local_sha_file}"
|
||||
fi
|
||||
if [ "$?" -ne 0 ]; then
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
err "Failed to download ${remote_url}"
|
||||
fi
|
||||
}
|
||||
|
||||
verify_hash() {
|
||||
remote_sha256="$1"
|
||||
local_file="$2"
|
||||
local_sha_file="${local_file}.sha256"
|
||||
|
||||
if [ -n "${CFG_SAVE}" ]; then
|
||||
if [ -f "${local_sha_file}" ]; then
|
||||
msg "Local ${local_sha_file} exists, treating as remote hash"
|
||||
remote_sha256=`cat "${local_sha_file}"`
|
||||
else
|
||||
download_hash
|
||||
fi
|
||||
else
|
||||
download_hash
|
||||
fi
|
||||
|
||||
msg "Verifying hash"
|
||||
local_sha256=$(calculate_hash "${local_file}")
|
||||
|
@ -13,14 +13,11 @@
|
||||
extern crate syntax;
|
||||
extern crate rustc;
|
||||
|
||||
extern crate regex;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io::File;
|
||||
use regex::Regex;
|
||||
|
||||
use syntax::parse;
|
||||
use syntax::parse::lexer;
|
||||
@ -167,15 +164,19 @@ fn count(lit: &str) -> usize {
|
||||
}
|
||||
|
||||
fn parse_antlr_token(s: &str, tokens: &HashMap<String, token::Token>) -> TokenAndSpan {
|
||||
let re = Regex::new(
|
||||
r"\[@(?P<seq>\d+),(?P<start>\d+):(?P<end>\d+)='(?P<content>.+?)',<(?P<toknum>-?\d+)>,\d+:\d+]"
|
||||
).unwrap();
|
||||
// old regex:
|
||||
// \[@(?P<seq>\d+),(?P<start>\d+):(?P<end>\d+)='(?P<content>.+?)',<(?P<toknum>-?\d+)>,\d+:\d+]
|
||||
let start = s.find_str("[@").unwrap();
|
||||
let comma = start + s[start..].find_str(",").unwrap();
|
||||
let colon = comma + s[comma..].find_str(":").unwrap();
|
||||
let content_start = colon + s[colon..].find_str("='").unwrap();
|
||||
let content_end = content_start + s[content_start..].find_str("',<").unwrap();
|
||||
let toknum_end = content_end + s[content_end..].find_str(">,").unwrap();
|
||||
|
||||
let m = re.captures(s).expect(format!("The regex didn't match {}", s).as_slice());
|
||||
let start = m.name("start").unwrap_or("");
|
||||
let end = m.name("end").unwrap_or("");
|
||||
let toknum = m.name("toknum").unwrap_or("");
|
||||
let content = m.name("content").unwrap_or("");
|
||||
let start = &s[comma + 1 .. colon];
|
||||
let end = &s[colon + 1 .. content_start];
|
||||
let content = &s[content_start + 2 .. content_end];
|
||||
let toknum = &s[content_end + 3 .. toknum_end];
|
||||
|
||||
let proto_tok = tokens.get(toknum).expect(format!("didn't find token {:?} in the map",
|
||||
toknum).as_slice());
|
||||
|
@ -72,7 +72,7 @@ use core::prelude::*;
|
||||
use core::atomic;
|
||||
use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst};
|
||||
use core::borrow::BorrowFrom;
|
||||
use core::fmt::{self, Show};
|
||||
use core::fmt;
|
||||
use core::cmp::{Ordering};
|
||||
use core::default::Default;
|
||||
use core::mem::{min_align_of, size_of};
|
||||
@ -582,16 +582,17 @@ impl<T: Ord> Ord for Arc<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Eq> Eq for Arc<T> {}
|
||||
|
||||
impl<T: fmt::Show> fmt::Show for Arc<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Display> fmt::Display for Arc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Arc({:?})", (**self))
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::String> fmt::String for Arc<T> {
|
||||
impl<T: fmt::Debug> fmt::Debug for Arc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt(&**self, f)
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -809,7 +810,7 @@ mod tests {
|
||||
#[test]
|
||||
fn show_arc() {
|
||||
let a = Arc::new(5u32);
|
||||
assert!(format!("{:?}", a) == "Arc(5u32)")
|
||||
assert_eq!(format!("{:?}", a), "5");
|
||||
}
|
||||
|
||||
// Make sure deriving works with Arc<T>
|
||||
|
@ -8,7 +8,40 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A unique pointer type.
|
||||
//! A pointer type for heap allocation.
|
||||
//!
|
||||
//! `Box<T>`, casually referred to as a 'box', provides the simplest form of heap allocation in
|
||||
//! Rust. Boxes provide ownership for this allocation, and drop their contents when they go out of
|
||||
//! scope.
|
||||
//!
|
||||
//! Boxes are useful in two situations: recursive data structures, and occasionally when returning
|
||||
//! data. [The Pointer chapter of the Book](../../../book/pointers.html#best-practices-1) explains
|
||||
//! these cases in detail.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Creating a box:
|
||||
//!
|
||||
//! ```
|
||||
//! let x = Box::new(5);
|
||||
//! ```
|
||||
//!
|
||||
//! Creating a recursive data structure:
|
||||
//!
|
||||
//! ```
|
||||
//! #[derive(Show)]
|
||||
//! enum List<T> {
|
||||
//! Cons(T, Box<List<T>>),
|
||||
//! Nil,
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
|
||||
//! println!("{:?}", list);
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This will print `Cons(1i32, Box(Cons(2i32, Box(Nil))))`.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
@ -16,19 +49,21 @@ use core::any::Any;
|
||||
use core::clone::Clone;
|
||||
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
|
||||
use core::default::Default;
|
||||
use core::error::{Error, FromError};
|
||||
use core::fmt;
|
||||
use core::hash::{self, Hash};
|
||||
use core::iter::Iterator;
|
||||
use core::marker::Sized;
|
||||
use core::mem;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::option::Option;
|
||||
use core::ptr::Unique;
|
||||
use core::raw::TraitObject;
|
||||
use core::result::Result;
|
||||
use core::result::Result::{Ok, Err};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::result::Result;
|
||||
|
||||
/// A value that represents the global exchange heap. This is the default
|
||||
/// place that the `box` keyword allocates into when no place is supplied.
|
||||
/// A value that represents the heap. This is the default place that the `box` keyword allocates
|
||||
/// into when no place is supplied.
|
||||
///
|
||||
/// The following two examples are equivalent:
|
||||
///
|
||||
@ -37,10 +72,8 @@ use core::ops::{Deref, DerefMut};
|
||||
/// use std::boxed::HEAP;
|
||||
///
|
||||
/// fn main() {
|
||||
/// # struct Bar;
|
||||
/// # impl Bar { fn new(_a: int) { } }
|
||||
/// let foo = box(HEAP) Bar::new(2);
|
||||
/// let foo = box Bar::new(2);
|
||||
/// let foo = box(HEAP) 5;
|
||||
/// let foo = box 5;
|
||||
/// }
|
||||
/// ```
|
||||
#[lang = "exchange_heap"]
|
||||
@ -48,13 +81,21 @@ use core::ops::{Deref, DerefMut};
|
||||
reason = "may be renamed; uncertain about custom allocator design")]
|
||||
pub static HEAP: () = ();
|
||||
|
||||
/// A type that represents a uniquely-owned value.
|
||||
/// A pointer type for heap allocation.
|
||||
///
|
||||
/// See the [module-level documentation](../../std/boxed/index.html) for more.
|
||||
#[lang = "owned_box"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Box<T>(Unique<T>);
|
||||
|
||||
impl<T> Box<T> {
|
||||
/// Moves `x` into a freshly allocated box on the global exchange heap.
|
||||
/// Allocates memory on the heap and then moves `x` into it.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let x = Box::new(5);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn new(x: T) -> Box<T> {
|
||||
box x
|
||||
@ -75,11 +116,29 @@ impl<T> Default for Box<[T]> {
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Clone> Clone for Box<T> {
|
||||
/// Returns a copy of the owned box.
|
||||
/// Returns a new box with a `clone()` of this box's contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let x = Box::new(5);
|
||||
/// let y = x.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Box<T> { box {(**self).clone()} }
|
||||
|
||||
/// Performs copy-assignment from `source` by reusing the existing allocation.
|
||||
/// Copies `source`'s contents into `self` without creating a new allocation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let x = Box::new(5);
|
||||
/// let mut y = Box::new(10);
|
||||
///
|
||||
/// y.clone_from(&x);
|
||||
///
|
||||
/// assert_eq!(*y, 5);
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone_from(&mut self, source: &Box<T>) {
|
||||
(**self).clone_from(&(**source));
|
||||
@ -158,20 +217,22 @@ impl BoxAny for Box<Any> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + fmt::Show> fmt::Show for Box<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Display + ?Sized> fmt::Display for Box<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Box({:?})", &**self)
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + fmt::String> fmt::String for Box<T> {
|
||||
impl<T: fmt::Debug + ?Sized> fmt::Debug for Box<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt(&**self, f)
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Show for Box<Any> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Debug for Box<Any> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad("Box<Any>")
|
||||
}
|
||||
@ -189,56 +250,22 @@ impl<T: ?Sized> DerefMut for Box<T> {
|
||||
fn deref_mut(&mut self) -> &mut T { &mut **self }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
fn test_owned_clone() {
|
||||
let a = Box::new(5i);
|
||||
let b: Box<int> = a.clone();
|
||||
assert!(a == b);
|
||||
// FIXME(#21363) remove `old_impl_check` when bug is fixed
|
||||
#[old_impl_check]
|
||||
impl<'a, T> Iterator for Box<Iterator<Item=T> + 'a> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
(**self).next()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn any_move() {
|
||||
let a = Box::new(8u) as Box<Any>;
|
||||
let b = Box::new(Test) as Box<Any>;
|
||||
|
||||
match a.downcast::<uint>() {
|
||||
Ok(a) => { assert!(a == Box::new(8u)); }
|
||||
Err(..) => panic!()
|
||||
}
|
||||
match b.downcast::<Test>() {
|
||||
Ok(a) => { assert!(a == Box::new(Test)); }
|
||||
Err(..) => panic!()
|
||||
}
|
||||
|
||||
let a = Box::new(8u) as Box<Any>;
|
||||
let b = Box::new(Test) as Box<Any>;
|
||||
|
||||
assert!(a.downcast::<Box<Test>>().is_err());
|
||||
assert!(b.downcast::<Box<uint>>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_show() {
|
||||
let a = Box::new(8u) as Box<Any>;
|
||||
let b = Box::new(Test) as Box<Any>;
|
||||
let a_str = a.to_str();
|
||||
let b_str = b.to_str();
|
||||
assert_eq!(a_str, "Box<Any>");
|
||||
assert_eq!(b_str, "Box<Any>");
|
||||
|
||||
let a = &8u as &Any;
|
||||
let b = &Test as &Any;
|
||||
let s = format!("{}", a);
|
||||
assert_eq!(s, "&Any");
|
||||
let s = format!("{}", b);
|
||||
assert_eq!(s, "&Any");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deref() {
|
||||
fn homura<T: Deref<Target=i32>>(_: T) { }
|
||||
homura(Box::new(765i32));
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(**self).size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: Error + 'a> FromError<E> for Box<Error + 'a> {
|
||||
fn from_error(err: E) -> Box<Error + 'a> {
|
||||
Box::new(err)
|
||||
}
|
||||
}
|
||||
|
75
src/liballoc/boxed_test.rs
Normal file
75
src/liballoc/boxed_test.rs
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2012-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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Test for `boxed` mod.
|
||||
|
||||
use core::any::Any;
|
||||
use core::ops::Deref;
|
||||
use core::result::Result::{Ok, Err};
|
||||
use core::clone::Clone;
|
||||
|
||||
use std::boxed::Box;
|
||||
use std::boxed::BoxAny;
|
||||
|
||||
#[test]
|
||||
fn test_owned_clone() {
|
||||
let a = Box::new(5i);
|
||||
let b: Box<int> = a.clone();
|
||||
assert!(a == b);
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct Test;
|
||||
|
||||
#[test]
|
||||
fn any_move() {
|
||||
let a = Box::new(8u) as Box<Any>;
|
||||
let b = Box::new(Test) as Box<Any>;
|
||||
|
||||
match a.downcast::<uint>() {
|
||||
Ok(a) => { assert!(a == Box::new(8u)); }
|
||||
Err(..) => panic!()
|
||||
}
|
||||
match b.downcast::<Test>() {
|
||||
Ok(a) => { assert!(a == Box::new(Test)); }
|
||||
Err(..) => panic!()
|
||||
}
|
||||
|
||||
let a = Box::new(8u) as Box<Any>;
|
||||
let b = Box::new(Test) as Box<Any>;
|
||||
|
||||
assert!(a.downcast::<Box<Test>>().is_err());
|
||||
assert!(b.downcast::<Box<uint>>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_show() {
|
||||
let a = Box::new(8u) as Box<Any>;
|
||||
let b = Box::new(Test) as Box<Any>;
|
||||
let a_str = format!("{:?}", a);
|
||||
let b_str = format!("{:?}", b);
|
||||
assert_eq!(a_str, "Box<Any>");
|
||||
assert_eq!(b_str, "Box<Any>");
|
||||
|
||||
static EIGHT: usize = 8us;
|
||||
static TEST: Test = Test;
|
||||
let a = &EIGHT as &Any;
|
||||
let b = &TEST as &Any;
|
||||
let s = format!("{:?}", a);
|
||||
assert_eq!(s, "&Any");
|
||||
let s = format!("{:?}", b);
|
||||
assert_eq!(s, "&Any");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deref() {
|
||||
fn homura<T: Deref<Target=i32>>(_: T) { }
|
||||
homura(Box::new(765i32));
|
||||
}
|
@ -280,7 +280,7 @@ mod imp {
|
||||
if align <= MIN_ALIGN {
|
||||
libc::malloc(size as libc::size_t) as *mut u8
|
||||
} else {
|
||||
let mut out = 0 as *mut libc::c_void;
|
||||
let mut out = ptr::null_mut();
|
||||
let ret = posix_memalign(&mut out,
|
||||
align as libc::size_t,
|
||||
size as libc::size_t);
|
||||
|
@ -70,6 +70,8 @@
|
||||
#![feature(lang_items, unsafe_destructor)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
// FIXME(#21363) remove `old_impl_check` when bug is fixed
|
||||
#![feature(old_impl_check)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![feature(core)]
|
||||
#![feature(hash)]
|
||||
@ -94,6 +96,8 @@ pub mod heap;
|
||||
|
||||
#[cfg(not(test))]
|
||||
pub mod boxed;
|
||||
#[cfg(test)]
|
||||
mod boxed_test;
|
||||
pub mod arc;
|
||||
pub mod rc;
|
||||
|
||||
|
@ -173,32 +173,15 @@ struct RcBox<T> {
|
||||
///
|
||||
/// See the [module level documentation](../index.html) for more details.
|
||||
#[unsafe_no_drop_flag]
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Rc<T> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with field accesses of the contained
|
||||
// type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
_nosend: marker::NoSend,
|
||||
_noshare: marker::NoSync
|
||||
}
|
||||
|
||||
/// An immutable reference-counted pointer type.
|
||||
///
|
||||
/// See the [module level documentation](../index.html) for more details.
|
||||
#[unsafe_no_drop_flag]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub struct Rc<T> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with field accesses of the contained
|
||||
// type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
impl<T> !marker::Send for Rc<T> {}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
impl<T> !marker::Sync for Rc<T> {}
|
||||
|
||||
impl<T> Rc<T> {
|
||||
@ -211,36 +194,7 @@ impl<T> Rc<T> {
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
/// ```
|
||||
#[cfg(stage0)] // NOTE remove after next snapshot
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn new(value: T) -> Rc<T> {
|
||||
unsafe {
|
||||
Rc {
|
||||
// there is an implicit weak pointer owned by all the strong pointers, which
|
||||
// ensures that the weak destructor never frees the allocation while the strong
|
||||
// destructor is running, even if the weak pointer is stored inside the strong one.
|
||||
_ptr: NonZero::new(transmute(box RcBox {
|
||||
value: value,
|
||||
strong: Cell::new(1),
|
||||
weak: Cell::new(1)
|
||||
})),
|
||||
_nosend: marker::NoSend,
|
||||
_noshare: marker::NoSync
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new `Rc<T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub fn new(value: T) -> Rc<T> {
|
||||
unsafe {
|
||||
Rc {
|
||||
@ -267,30 +221,6 @@ impl<T> Rc<T> {
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
/// ```
|
||||
#[cfg(stage0)] // NOTE remove after next snapshot
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module")]
|
||||
pub fn downgrade(&self) -> Weak<T> {
|
||||
self.inc_weak();
|
||||
Weak {
|
||||
_ptr: self._ptr,
|
||||
_nosend: marker::NoSend,
|
||||
_noshare: marker::NoSync
|
||||
}
|
||||
}
|
||||
|
||||
/// Downgrades the `Rc<T>` to a `Weak<T>` reference.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
/// ```
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module")]
|
||||
pub fn downgrade(&self) -> Weak<T> {
|
||||
@ -485,25 +415,6 @@ impl<T> Drop for Rc<T> {
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Clone for Rc<T> {
|
||||
/// Makes a clone of the `Rc<T>`.
|
||||
///
|
||||
/// This increases the strong reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[cfg(stage0)] // NOTE remove after next snapshot
|
||||
fn clone(&self) -> Rc<T> {
|
||||
self.inc_strong();
|
||||
Rc { _ptr: self._ptr, _nosend: marker::NoSend, _noshare: marker::NoSync }
|
||||
}
|
||||
|
||||
/// Makes a clone of the `Rc<T>`.
|
||||
///
|
||||
@ -519,7 +430,6 @@ impl<T> Clone for Rc<T> {
|
||||
/// five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
fn clone(&self) -> Rc<T> {
|
||||
self.inc_strong();
|
||||
Rc { _ptr: self._ptr }
|
||||
@ -695,17 +605,17 @@ impl<S: hash::Hasher, T: Hash<S>> Hash<S> for Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "alloc", reason = "Show is experimental.")]
|
||||
impl<T: fmt::Show> fmt::Show for Rc<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Display> fmt::Display for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Rc({:?})", **self)
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::String> fmt::String for Rc<T> {
|
||||
impl<T: fmt::Debug> fmt::Debug for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt(&**self, f)
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -715,68 +625,22 @@ impl<T: fmt::String> fmt::String for Rc<T> {
|
||||
///
|
||||
/// See the [module level documentation](../index.html) for more.
|
||||
#[unsafe_no_drop_flag]
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
pub struct Weak<T> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
_nosend: marker::NoSend,
|
||||
_noshare: marker::NoSync
|
||||
}
|
||||
|
||||
/// A weak version of `Rc<T>`.
|
||||
///
|
||||
/// Weak references do not count when determining if the inner value should be dropped.
|
||||
///
|
||||
/// See the [module level documentation](../index.html) for more.
|
||||
#[unsafe_no_drop_flag]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub struct Weak<T> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
impl<T> !marker::Send for Weak<T> {}
|
||||
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
impl<T> !marker::Sync for Weak<T> {}
|
||||
|
||||
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T> Weak<T> {
|
||||
/// Upgrades a weak reference to a strong reference.
|
||||
///
|
||||
/// Upgrades the `Weak<T>` reference to an `Rc<T>`, if possible.
|
||||
///
|
||||
/// Returns `None` if there were no strong references and the data was destroyed.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// let strong_five: Option<Rc<_>> = weak_five.upgrade();
|
||||
/// ```
|
||||
#[cfg(stage0)] // NOTE remove after next snapshot
|
||||
pub fn upgrade(&self) -> Option<Rc<T>> {
|
||||
if self.strong() == 0 {
|
||||
None
|
||||
} else {
|
||||
self.inc_strong();
|
||||
Some(Rc { _ptr: self._ptr, _nosend: marker::NoSend, _noshare: marker::NoSync })
|
||||
}
|
||||
}
|
||||
|
||||
/// Upgrades a weak reference to a strong reference.
|
||||
///
|
||||
@ -795,7 +659,6 @@ impl<T> Weak<T> {
|
||||
///
|
||||
/// let strong_five: Option<Rc<_>> = weak_five.upgrade();
|
||||
/// ```
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
pub fn upgrade(&self) -> Option<Rc<T>> {
|
||||
if self.strong() == 0 {
|
||||
None
|
||||
@ -853,25 +716,6 @@ impl<T> Drop for Weak<T> {
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T> Clone for Weak<T> {
|
||||
/// Makes a clone of the `Weak<T>`.
|
||||
///
|
||||
/// This increases the weak reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let weak_five = Rc::new(5i).downgrade();
|
||||
///
|
||||
/// weak_five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[cfg(stage0)] // NOTE remove after next snapshot
|
||||
fn clone(&self) -> Weak<T> {
|
||||
self.inc_weak();
|
||||
Weak { _ptr: self._ptr, _nosend: marker::NoSend, _noshare: marker::NoSync }
|
||||
}
|
||||
|
||||
/// Makes a clone of the `Weak<T>`.
|
||||
///
|
||||
@ -887,15 +731,14 @@ impl<T> Clone for Weak<T> {
|
||||
/// weak_five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[cfg(not(stage0))] // NOTE remove cfg after next snapshot
|
||||
fn clone(&self) -> Weak<T> {
|
||||
self.inc_weak();
|
||||
Weak { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "alloc", reason = "Show is experimental.")]
|
||||
impl<T: fmt::Show> fmt::Show for Weak<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Debug> fmt::Debug for Weak<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(Weak)")
|
||||
}
|
||||
@ -1137,7 +980,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_show() {
|
||||
let foo = Rc::new(75u);
|
||||
assert!(format!("{:?}", foo) == "Rc(75u)")
|
||||
assert_eq!(format!("{:?}", foo), "75");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ impl Bitv {
|
||||
|
||||
if extra_bytes > 0 {
|
||||
let mut last_word = 0u32;
|
||||
for (i, &byte) in bytes[(complete_words*4)..].iter().enumerate() {
|
||||
for (i, &byte) in bytes[complete_words*4..].iter().enumerate() {
|
||||
last_word |= (reverse_bits(byte) as u32) << (i * 8);
|
||||
}
|
||||
bitv.storage.push(last_word);
|
||||
@ -974,7 +974,7 @@ impl Ord for Bitv {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Show for Bitv {
|
||||
impl fmt::Debug for Bitv {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
for bit in self.iter() {
|
||||
try!(write!(fmt, "{}", if bit { 1u32 } else { 0u32 }));
|
||||
@ -1730,7 +1730,7 @@ impl BitvSet {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Show for BitvSet {
|
||||
impl fmt::Debug for BitvSet {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(fmt, "BitvSet {{"));
|
||||
let mut first = true;
|
||||
@ -2625,7 +2625,7 @@ mod bitv_set_test {
|
||||
s.insert(10);
|
||||
s.insert(50);
|
||||
s.insert(2);
|
||||
assert_eq!("BitvSet {1u, 2u, 10u, 50u}", format!("{:?}", s));
|
||||
assert_eq!("BitvSet {1, 2, 10, 50}", format!("{:?}", s));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -22,7 +22,7 @@ use core::prelude::*;
|
||||
use core::borrow::BorrowFrom;
|
||||
use core::cmp::Ordering;
|
||||
use core::default::Default;
|
||||
use core::fmt::Show;
|
||||
use core::fmt::Debug;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::iter::{Map, FromIterator};
|
||||
use core::ops::{Index, IndexMut};
|
||||
@ -874,7 +874,7 @@ impl<K: Ord, V: Ord> Ord for BTreeMap<K, V> {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: Show, V: Show> Show for BTreeMap<K, V> {
|
||||
impl<K: Debug, V: Debug> Debug for BTreeMap<K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "BTreeMap {{"));
|
||||
|
||||
|
@ -21,7 +21,7 @@ use core::prelude::*;
|
||||
use core::borrow::BorrowFrom;
|
||||
use core::cmp::Ordering::{Greater, Less, Equal};
|
||||
use core::iter::Zip;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::ops::{Deref, DerefMut, Index, IndexMut};
|
||||
use core::ptr::Unique;
|
||||
use core::{slice, mem, ptr, cmp, num, raw};
|
||||
use alloc::heap;
|
||||
@ -1487,7 +1487,7 @@ impl<K, V, E, Impl> AbsTraversal<Impl>
|
||||
|
||||
macro_rules! node_slice_impl {
|
||||
($NodeSlice:ident, $Traversal:ident,
|
||||
$as_slices_internal:ident, $slice_from:ident, $slice_to:ident, $iter:ident) => {
|
||||
$as_slices_internal:ident, $index:ident, $iter:ident) => {
|
||||
impl<'a, K: Ord + 'a, V: 'a> $NodeSlice<'a, K, V> {
|
||||
/// Performs linear search in a slice. Returns a tuple of (index, is_exact_match).
|
||||
fn search_linear<Q: ?Sized>(&self, key: &Q) -> (uint, bool)
|
||||
@ -1521,10 +1521,10 @@ macro_rules! node_slice_impl {
|
||||
edges: if !self.has_edges {
|
||||
self.edges
|
||||
} else {
|
||||
self.edges.$slice_from(pos)
|
||||
self.edges.$index(&(pos ..))
|
||||
},
|
||||
keys: self.keys.slice_from(pos),
|
||||
vals: self.vals.$slice_from(pos),
|
||||
keys: &self.keys[pos ..],
|
||||
vals: self.vals.$index(&(pos ..)),
|
||||
head_is_edge: !pos_is_kv,
|
||||
tail_is_edge: self.tail_is_edge,
|
||||
}
|
||||
@ -1550,10 +1550,10 @@ macro_rules! node_slice_impl {
|
||||
edges: if !self.has_edges {
|
||||
self.edges
|
||||
} else {
|
||||
self.edges.$slice_to(pos + 1)
|
||||
self.edges.$index(&(.. (pos + 1)))
|
||||
},
|
||||
keys: self.keys.slice_to(pos),
|
||||
vals: self.vals.$slice_to(pos),
|
||||
keys: &self.keys[..pos],
|
||||
vals: self.vals.$index(&(.. pos)),
|
||||
head_is_edge: self.head_is_edge,
|
||||
tail_is_edge: !pos_is_kv,
|
||||
}
|
||||
@ -1583,6 +1583,5 @@ macro_rules! node_slice_impl {
|
||||
}
|
||||
}
|
||||
|
||||
node_slice_impl!(NodeSlice, Traversal, as_slices_internal, slice_from, slice_to, iter);
|
||||
node_slice_impl!(MutNodeSlice, MutTraversal, as_slices_internal_mut, slice_from_mut,
|
||||
slice_to_mut, iter_mut);
|
||||
node_slice_impl!(NodeSlice, Traversal, as_slices_internal, index, iter);
|
||||
node_slice_impl!(MutNodeSlice, MutTraversal, as_slices_internal_mut, index_mut, iter_mut);
|
||||
|
@ -16,11 +16,8 @@ use core::prelude::*;
|
||||
use core::borrow::BorrowFrom;
|
||||
use core::cmp::Ordering::{self, Less, Greater, Equal};
|
||||
use core::default::Default;
|
||||
use core::fmt::Show;
|
||||
use core::fmt::Debug;
|
||||
use core::fmt;
|
||||
// NOTE(stage0) remove import after a snapshot
|
||||
#[cfg(stage0)]
|
||||
use core::hash::Hash;
|
||||
use core::iter::{Peekable, Map, FromIterator};
|
||||
use core::ops::{BitOr, BitAnd, BitXor, Sub};
|
||||
|
||||
@ -594,7 +591,7 @@ impl<'a, 'b, T: Ord + Clone> BitOr<&'b BTreeSet<T>> for &'a BTreeSet<T> {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Show> Show for BTreeSet<T> {
|
||||
impl<T: Debug> Debug for BTreeSet<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "BTreeSet {{"));
|
||||
|
||||
@ -894,7 +891,7 @@ mod test {
|
||||
|
||||
let set_str = format!("{:?}", set);
|
||||
|
||||
assert_eq!(set_str, "BTreeSet {1i, 2i}");
|
||||
assert_eq!(set_str, "BTreeSet {1, 2}");
|
||||
assert_eq!(format!("{:?}", empty), "BTreeSet {}");
|
||||
}
|
||||
}
|
||||
|
@ -876,7 +876,7 @@ impl<A: Clone> Clone for DList<A> {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: fmt::Show> fmt::Show for DList<A> {
|
||||
impl<A: fmt::Debug> fmt::Debug for DList<A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "DList ["));
|
||||
|
||||
@ -1335,7 +1335,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_show() {
|
||||
let list: DList<int> = range(0i, 10).collect();
|
||||
assert_eq!(format!("{:?}", list), "DList [0i, 1i, 2i, 3i, 4i, 5i, 6i, 7i, 8i, 9i]");
|
||||
assert_eq!(format!("{:?}", list), "DList [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
|
||||
|
||||
let list: DList<&str> = vec!["just", "one", "test", "more"].iter()
|
||||
.map(|&s| s)
|
||||
|
@ -31,7 +31,7 @@ pub struct EnumSet<E> {
|
||||
|
||||
impl<E> Copy for EnumSet<E> {}
|
||||
|
||||
impl<E:CLike+fmt::Show> fmt::Show for EnumSet<E> {
|
||||
impl<E:CLike + fmt::Debug> fmt::Debug for EnumSet<E> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(fmt, "EnumSet {{"));
|
||||
let mut first = true;
|
||||
|
@ -12,13 +12,13 @@
|
||||
#[macro_export]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
macro_rules! vec {
|
||||
($x:expr; $y:expr) => ({
|
||||
let xs: $crate::boxed::Box<[_]> = $crate::boxed::Box::new([$x; $y]);
|
||||
$crate::slice::SliceExt::into_vec(xs)
|
||||
});
|
||||
($($x:expr),*) => ({
|
||||
let xs: $crate::boxed::Box<[_]> = $crate::boxed::Box::new([$($x),*]);
|
||||
$crate::slice::SliceExt::into_vec(xs)
|
||||
});
|
||||
($x:expr; $y:expr) => (
|
||||
<[_] as $crate::slice::SliceExt>::into_vec(
|
||||
$crate::boxed::Box::new([$x; $y]))
|
||||
);
|
||||
($($x:expr),*) => (
|
||||
<[_] as $crate::slice::SliceExt>::into_vec(
|
||||
$crate::boxed::Box::new([$($x),*]))
|
||||
);
|
||||
($($x:expr,)*) => (vec![$($x),*])
|
||||
}
|
||||
|
@ -581,7 +581,7 @@ impl<T> RingBuf<T> {
|
||||
|
||||
if contiguous {
|
||||
let (empty, buf) = buf.split_at_mut(0);
|
||||
(buf.slice_mut(tail, head), empty)
|
||||
(&mut buf[tail .. head], empty)
|
||||
} else {
|
||||
let (mid, right) = buf.split_at_mut(tail);
|
||||
let (left, _) = mid.split_at_mut(head);
|
||||
@ -1619,7 +1619,7 @@ impl<A> Extend<A> for RingBuf<A> {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Show> fmt::Show for RingBuf<T> {
|
||||
impl<T: fmt::Debug> fmt::Debug for RingBuf<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "RingBuf ["));
|
||||
|
||||
@ -1638,7 +1638,7 @@ mod tests {
|
||||
use self::Taggypar::*;
|
||||
use prelude::*;
|
||||
use core::iter;
|
||||
use std::fmt::Show;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::{self, SipHasher};
|
||||
use test::Bencher;
|
||||
use test;
|
||||
@ -1686,7 +1686,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn test_parameterized<T:Clone + PartialEq + Show>(a: T, b: T, c: T, d: T) {
|
||||
fn test_parameterized<T:Clone + PartialEq + Debug>(a: T, b: T, c: T, d: T) {
|
||||
let mut deq = RingBuf::new();
|
||||
assert_eq!(deq.len(), 0);
|
||||
deq.push_front(a.clone());
|
||||
@ -2310,7 +2310,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_show() {
|
||||
let ringbuf: RingBuf<int> = range(0i, 10).collect();
|
||||
assert_eq!(format!("{:?}", ringbuf), "RingBuf [0i, 1i, 2i, 3i, 4i, 5i, 6i, 7i, 8i, 9i]");
|
||||
assert_eq!(format!("{:?}", ringbuf), "RingBuf [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
|
||||
|
||||
let ringbuf: RingBuf<&str> = vec!["just", "one", "test", "more"].iter()
|
||||
.map(|&s| s)
|
||||
|
@ -170,32 +170,22 @@ pub trait SliceExt {
|
||||
reason = "uncertain about this API approach")]
|
||||
fn move_from(&mut self, src: Vec<Self::Item>, start: uint, end: uint) -> uint;
|
||||
|
||||
/// Returns a subslice spanning the interval [`start`, `end`).
|
||||
///
|
||||
/// Panics when the end of the new slice lies beyond the end of the
|
||||
/// original slice (i.e. when `end > self.len()`) or when `start > end`.
|
||||
///
|
||||
/// Slicing with `start` equal to `end` yields an empty slice.
|
||||
/// Deprecated: use `&s[start .. end]` notation instead.
|
||||
#[unstable(feature = "collections",
|
||||
reason = "will be replaced by slice syntax")]
|
||||
#[deprecated(since = "1.0.0", reason = "use &s[start .. end] instead")]
|
||||
fn slice(&self, start: uint, end: uint) -> &[Self::Item];
|
||||
|
||||
/// Returns a subslice from `start` to the end of the slice.
|
||||
///
|
||||
/// Panics when `start` is strictly greater than the length of the original slice.
|
||||
///
|
||||
/// Slicing from `self.len()` yields an empty slice.
|
||||
/// Deprecated: use `&s[start..]` notation instead.
|
||||
#[unstable(feature = "collections",
|
||||
reason = "will be replaced by slice syntax")]
|
||||
#[deprecated(since = "1.0.0", reason = "use &s[start..] isntead")]
|
||||
fn slice_from(&self, start: uint) -> &[Self::Item];
|
||||
|
||||
/// Returns a subslice from the start of the slice to `end`.
|
||||
///
|
||||
/// Panics when `end` is strictly greater than the length of the original slice.
|
||||
///
|
||||
/// Slicing to `0` yields an empty slice.
|
||||
/// Deprecated: use `&s[..end]` notation instead.
|
||||
#[unstable(feature = "collections",
|
||||
reason = "will be replaced by slice syntax")]
|
||||
#[deprecated(since = "1.0.0", reason = "use &s[..end] instead")]
|
||||
fn slice_to(&self, end: uint) -> &[Self::Item];
|
||||
|
||||
/// Divides one slice into two at an index.
|
||||
@ -382,32 +372,22 @@ pub trait SliceExt {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn as_mut_slice(&mut self) -> &mut [Self::Item];
|
||||
|
||||
/// Returns a mutable subslice spanning the interval [`start`, `end`).
|
||||
///
|
||||
/// Panics when the end of the new slice lies beyond the end of the
|
||||
/// original slice (i.e. when `end > self.len()`) or when `start > end`.
|
||||
///
|
||||
/// Slicing with `start` equal to `end` yields an empty slice.
|
||||
/// Deprecated: use `&mut s[start .. end]` instead.
|
||||
#[unstable(feature = "collections",
|
||||
reason = "will be replaced by slice syntax")]
|
||||
#[deprecated(since = "1.0.0", reason = "use &mut s[start .. end] instead")]
|
||||
fn slice_mut(&mut self, start: uint, end: uint) -> &mut [Self::Item];
|
||||
|
||||
/// Returns a mutable subslice from `start` to the end of the slice.
|
||||
///
|
||||
/// Panics when `start` is strictly greater than the length of the original slice.
|
||||
///
|
||||
/// Slicing from `self.len()` yields an empty slice.
|
||||
/// Deprecated: use `&mut s[start ..]` instead.
|
||||
#[unstable(feature = "collections",
|
||||
reason = "will be replaced by slice syntax")]
|
||||
#[deprecated(since = "1.0.0", reason = "use &mut s[start ..] instead")]
|
||||
fn slice_from_mut(&mut self, start: uint) -> &mut [Self::Item];
|
||||
|
||||
/// Returns a mutable subslice from the start of the slice to `end`.
|
||||
///
|
||||
/// Panics when `end` is strictly greater than the length of the original slice.
|
||||
///
|
||||
/// Slicing to `0` yields an empty slice.
|
||||
/// Deprecated: use `&mut s[.. end]` instead.
|
||||
#[unstable(feature = "collections",
|
||||
reason = "will be replaced by slice syntax")]
|
||||
#[deprecated(since = "1.0.0", reason = "use &mut s[.. end] instead")]
|
||||
fn slice_to_mut(&mut self, end: uint) -> &mut [Self::Item];
|
||||
|
||||
/// Returns an iterator that allows modifying each value
|
||||
@ -724,7 +704,7 @@ impl<T> SliceExt for [T] {
|
||||
|
||||
#[inline]
|
||||
fn move_from(&mut self, mut src: Vec<T>, start: uint, end: uint) -> uint {
|
||||
for (a, b) in self.iter_mut().zip(src.slice_mut(start, end).iter_mut()) {
|
||||
for (a, b) in self.iter_mut().zip(src[start .. end].iter_mut()) {
|
||||
mem::swap(a, b);
|
||||
}
|
||||
cmp::min(self.len(), end-start)
|
||||
@ -732,17 +712,17 @@ impl<T> SliceExt for [T] {
|
||||
|
||||
#[inline]
|
||||
fn slice<'a>(&'a self, start: uint, end: uint) -> &'a [T] {
|
||||
core_slice::SliceExt::slice(self, start, end)
|
||||
&self[start .. end]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_from<'a>(&'a self, start: uint) -> &'a [T] {
|
||||
core_slice::SliceExt::slice_from(self, start)
|
||||
&self[start ..]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_to<'a>(&'a self, end: uint) -> &'a [T] {
|
||||
core_slice::SliceExt::slice_to(self, end)
|
||||
&self[.. end]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -846,17 +826,17 @@ impl<T> SliceExt for [T] {
|
||||
|
||||
#[inline]
|
||||
fn slice_mut<'a>(&'a mut self, start: uint, end: uint) -> &'a mut [T] {
|
||||
core_slice::SliceExt::slice_mut(self, start, end)
|
||||
&mut self[start .. end]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_from_mut<'a>(&'a mut self, start: uint) -> &'a mut [T] {
|
||||
core_slice::SliceExt::slice_from_mut(self, start)
|
||||
&mut self[start ..]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_to_mut<'a>(&'a mut self, end: uint) -> &'a mut [T] {
|
||||
core_slice::SliceExt::slice_to_mut(self, end)
|
||||
&mut self[.. end]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -1005,11 +985,30 @@ impl<T> SliceExt for [T] {
|
||||
/// An extension trait for concatenating slices
|
||||
pub trait SliceConcatExt<T: ?Sized, U> {
|
||||
/// Flattens a slice of `T` into a single value `U`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec!["hello", "world"];
|
||||
///
|
||||
/// let s: String = v.concat();
|
||||
///
|
||||
/// println!("{}", s); // prints "helloworld"
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn concat(&self) -> U;
|
||||
|
||||
/// Flattens a slice of `T` into a single value `U`, placing a
|
||||
/// given separator between each.
|
||||
/// Flattens a slice of `T` into a single value `U`, placing a given separator between each.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec!["hello", "world"];
|
||||
///
|
||||
/// let s: String = v.connect(" ");
|
||||
///
|
||||
/// println!("{}", s); // prints "hello world"
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn connect(&self, sep: &T) -> U;
|
||||
}
|
||||
@ -2421,8 +2420,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_chunksator() {
|
||||
use core::iter::ExactSizeIterator;
|
||||
|
||||
let v = &[1i,2,3,4,5];
|
||||
|
||||
assert_eq!(v.chunks(2).len(), 3);
|
||||
|
||||
let chunks: &[&[int]] = &[&[1i,2], &[3,4], &[5]];
|
||||
assert_eq!(v.chunks(2).collect::<Vec<&[int]>>(), chunks);
|
||||
let chunks: &[&[int]] = &[&[1i,2,3], &[4,5]];
|
||||
@ -2488,19 +2491,19 @@ mod tests {
|
||||
}
|
||||
let empty: Vec<int> = vec![];
|
||||
test_show_vec!(empty, "[]");
|
||||
test_show_vec!(vec![1i], "[1i]");
|
||||
test_show_vec!(vec![1i, 2, 3], "[1i, 2i, 3i]");
|
||||
test_show_vec!(vec![1i], "[1]");
|
||||
test_show_vec!(vec![1i, 2, 3], "[1, 2, 3]");
|
||||
test_show_vec!(vec![vec![], vec![1u], vec![1u, 1u]],
|
||||
"[[], [1u], [1u, 1u]]");
|
||||
"[[], [1], [1, 1]]");
|
||||
|
||||
let empty_mut: &mut [int] = &mut[];
|
||||
test_show_vec!(empty_mut, "[]");
|
||||
let v: &mut[int] = &mut[1];
|
||||
test_show_vec!(v, "[1i]");
|
||||
test_show_vec!(v, "[1]");
|
||||
let v: &mut[int] = &mut[1, 2, 3];
|
||||
test_show_vec!(v, "[1i, 2i, 3i]");
|
||||
test_show_vec!(v, "[1, 2, 3]");
|
||||
let v: &mut [&mut[uint]] = &mut[&mut[], &mut[1u], &mut[1u, 1u]];
|
||||
test_show_vec!(v, "[[], [1u], [1u, 1u]]");
|
||||
test_show_vec!(v, "[[], [1], [1, 1]]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -2687,7 +2690,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_mut_chunks() {
|
||||
use core::iter::ExactSizeIterator;
|
||||
|
||||
let mut v = [0u8, 1, 2, 3, 4, 5, 6];
|
||||
assert_eq!(v.chunks_mut(2).len(), 4);
|
||||
for (i, chunk) in v.chunks_mut(3).enumerate() {
|
||||
for x in chunk.iter_mut() {
|
||||
*x = i as u8;
|
||||
|
@ -759,70 +759,23 @@ pub trait StrExt: Index<FullRange, Output = str> {
|
||||
core_str::StrExt::lines_any(&self[])
|
||||
}
|
||||
|
||||
/// Returns a slice of the given string from the byte range
|
||||
/// [`begin`..`end`).
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
///
|
||||
/// Panics when `begin` and `end` do not point to valid characters
|
||||
/// or point beyond the last character of the string.
|
||||
///
|
||||
/// See also `slice_to` and `slice_from` for slicing prefixes and
|
||||
/// suffixes of strings, and `slice_chars` for slicing based on
|
||||
/// code point counts.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let s = "Löwe 老虎 Léopard";
|
||||
/// assert_eq!(s.slice(0, 1), "L");
|
||||
///
|
||||
/// assert_eq!(s.slice(1, 9), "öwe 老");
|
||||
///
|
||||
/// // these will panic:
|
||||
/// // byte 2 lies within `ö`:
|
||||
/// // s.slice(2, 3);
|
||||
///
|
||||
/// // byte 8 lies within `老`
|
||||
/// // s.slice(1, 8);
|
||||
///
|
||||
/// // byte 100 is outside the string
|
||||
/// // s.slice(3, 100);
|
||||
/// ```
|
||||
/// Deprecated: use `s[a .. b]` instead.
|
||||
#[unstable(feature = "collections",
|
||||
reason = "use slice notation [a..b] instead")]
|
||||
fn slice(&self, begin: uint, end: uint) -> &str {
|
||||
core_str::StrExt::slice(&self[], begin, end)
|
||||
}
|
||||
#[deprecated(since = "1.0.0", reason = "use slice notation [a..b] instead")]
|
||||
fn slice(&self, begin: uint, end: uint) -> &str;
|
||||
|
||||
/// Returns a slice of the string from `begin` to its end.
|
||||
///
|
||||
/// Equivalent to `self.slice(begin, self.len())`.
|
||||
///
|
||||
/// Panics when `begin` does not point to a valid character, or is
|
||||
/// out of bounds.
|
||||
///
|
||||
/// See also `slice`, `slice_to` and `slice_chars`.
|
||||
/// Deprecated: use `s[a..]` instead.
|
||||
#[unstable(feature = "collections",
|
||||
reason = "use slice notation [a..] instead")]
|
||||
fn slice_from(&self, begin: uint) -> &str {
|
||||
core_str::StrExt::slice_from(&self[], begin)
|
||||
}
|
||||
reason = "use slice notation [a..b] instead")]
|
||||
#[deprecated(since = "1.0.0", reason = "use slice notation [a..] instead")]
|
||||
fn slice_from(&self, begin: uint) -> &str;
|
||||
|
||||
/// Returns a slice of the string from the beginning to byte
|
||||
/// `end`.
|
||||
///
|
||||
/// Equivalent to `self.slice(0, end)`.
|
||||
///
|
||||
/// Panics when `end` does not point to a valid character, or is
|
||||
/// out of bounds.
|
||||
///
|
||||
/// See also `slice`, `slice_from` and `slice_chars`.
|
||||
/// Deprecated: use `s[..a]` instead.
|
||||
#[unstable(feature = "collections",
|
||||
reason = "use slice notation [..a] instead")]
|
||||
fn slice_to(&self, end: uint) -> &str {
|
||||
core_str::StrExt::slice_to(&self[], end)
|
||||
}
|
||||
reason = "use slice notation [a..b] instead")]
|
||||
#[deprecated(since = "1.0.0", reason = "use slice notation [..a] instead")]
|
||||
fn slice_to(&self, end: uint) -> &str;
|
||||
|
||||
/// Returns a slice of the string from the character range
|
||||
/// [`begin`..`end`).
|
||||
@ -1374,7 +1327,19 @@ pub trait StrExt: Index<FullRange, Output = str> {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl StrExt for str {}
|
||||
impl StrExt for str {
|
||||
fn slice(&self, begin: uint, end: uint) -> &str {
|
||||
&self[begin..end]
|
||||
}
|
||||
|
||||
fn slice_from(&self, begin: uint) -> &str {
|
||||
&self[begin..]
|
||||
}
|
||||
|
||||
fn slice_to(&self, end: uint) -> &str {
|
||||
&self[..end]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
@ -18,6 +18,7 @@ use core::prelude::*;
|
||||
|
||||
use core::borrow::{Cow, IntoCow};
|
||||
use core::default::Default;
|
||||
use core::error::Error;
|
||||
use core::fmt;
|
||||
use core::hash;
|
||||
use core::iter::FromIterator;
|
||||
@ -40,6 +41,7 @@ pub struct String {
|
||||
|
||||
/// A possible error value from the `String::from_utf8` function.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(Show)]
|
||||
pub struct FromUtf8Error {
|
||||
bytes: Vec<u8>,
|
||||
error: Utf8Error,
|
||||
@ -48,6 +50,7 @@ pub struct FromUtf8Error {
|
||||
/// A possible error value from the `String::from_utf16` function.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(missing_copy_implementations)]
|
||||
#[derive(Show)]
|
||||
pub struct FromUtf16Error(());
|
||||
|
||||
impl String {
|
||||
@ -681,30 +684,28 @@ impl FromUtf8Error {
|
||||
pub fn utf8_error(&self) -> Utf8Error { self.error }
|
||||
}
|
||||
|
||||
impl fmt::Show for FromUtf8Error {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for FromUtf8Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt(self, f)
|
||||
fmt::Display::fmt(&self.error, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::String for FromUtf8Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt(&self.error, f)
|
||||
}
|
||||
impl Error for FromUtf8Error {
|
||||
fn description(&self) -> &str { "invalid utf-8" }
|
||||
}
|
||||
|
||||
impl fmt::Show for FromUtf16Error {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for FromUtf16Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt(self, f)
|
||||
fmt::Display::fmt("invalid utf-16: lone surrogate found", f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::String for FromUtf16Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt("invalid utf-16: lone surrogate found", f)
|
||||
}
|
||||
impl Error for FromUtf16Error {
|
||||
fn description(&self) -> &str { "invalid utf-16" }
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -817,18 +818,18 @@ impl Default for String {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::String for String {
|
||||
impl fmt::Display for String {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt(&**self, f)
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collections", reason = "waiting on fmt stabilization")]
|
||||
impl fmt::Show for String {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Debug for String {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Show::fmt(&**self, f)
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -852,6 +853,7 @@ impl<'a> Add<&'a str> for String {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ops::Index<ops::Range<uint>> for String {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
@ -859,6 +861,7 @@ impl ops::Index<ops::Range<uint>> for String {
|
||||
&self[][*index]
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ops::Index<ops::RangeTo<uint>> for String {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
@ -866,6 +869,7 @@ impl ops::Index<ops::RangeTo<uint>> for String {
|
||||
&self[][*index]
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ops::Index<ops::RangeFrom<uint>> for String {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
@ -873,6 +877,7 @@ impl ops::Index<ops::RangeFrom<uint>> for String {
|
||||
&self[][*index]
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ops::Index<ops::FullRange> for String {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
@ -938,7 +943,7 @@ pub trait ToString {
|
||||
fn to_string(&self) -> String;
|
||||
}
|
||||
|
||||
impl<T: fmt::String + ?Sized> ToString for T {
|
||||
impl<T: fmt::Display + ?Sized> ToString for T {
|
||||
#[inline]
|
||||
fn to_string(&self) -> String {
|
||||
use core::fmt::Writer;
|
||||
@ -1299,10 +1304,10 @@ mod tests {
|
||||
fn test_vectors() {
|
||||
let x: Vec<int> = vec![];
|
||||
assert_eq!(format!("{:?}", x), "[]");
|
||||
assert_eq!(format!("{:?}", vec![1i]), "[1i]");
|
||||
assert_eq!(format!("{:?}", vec![1i, 2, 3]), "[1i, 2i, 3i]");
|
||||
assert_eq!(format!("{:?}", vec![1i]), "[1]");
|
||||
assert_eq!(format!("{:?}", vec![1i, 2, 3]), "[1, 2, 3]");
|
||||
assert!(format!("{:?}", vec![vec![], vec![1i], vec![1i, 1]]) ==
|
||||
"[[], [1i], [1i, 1i]]");
|
||||
"[[], [1], [1, 1]]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1235,7 +1235,7 @@ impl<S: hash::Writer + hash::Hasher, T: Hash<S>> Hash<S> for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collections", reason = "waiting on Index stability")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Index<uint> for Vec<T> {
|
||||
type Output = T;
|
||||
|
||||
@ -1245,6 +1245,7 @@ impl<T> Index<uint> for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> IndexMut<uint> for Vec<T> {
|
||||
type Output = T;
|
||||
|
||||
@ -1255,6 +1256,7 @@ impl<T> IndexMut<uint> for Vec<T> {
|
||||
}
|
||||
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Index<ops::Range<uint>> for Vec<T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -1262,6 +1264,7 @@ impl<T> ops::Index<ops::Range<uint>> for Vec<T> {
|
||||
self.as_slice().index(index)
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Index<ops::RangeTo<uint>> for Vec<T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -1269,6 +1272,7 @@ impl<T> ops::Index<ops::RangeTo<uint>> for Vec<T> {
|
||||
self.as_slice().index(index)
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Index<ops::RangeFrom<uint>> for Vec<T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -1276,6 +1280,7 @@ impl<T> ops::Index<ops::RangeFrom<uint>> for Vec<T> {
|
||||
self.as_slice().index(index)
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Index<ops::FullRange> for Vec<T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -1284,6 +1289,7 @@ impl<T> ops::Index<ops::FullRange> for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::IndexMut<ops::Range<uint>> for Vec<T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -1291,6 +1297,7 @@ impl<T> ops::IndexMut<ops::Range<uint>> for Vec<T> {
|
||||
self.as_mut_slice().index_mut(index)
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::IndexMut<ops::RangeTo<uint>> for Vec<T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -1298,6 +1305,7 @@ impl<T> ops::IndexMut<ops::RangeTo<uint>> for Vec<T> {
|
||||
self.as_mut_slice().index_mut(index)
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::IndexMut<ops::RangeFrom<uint>> for Vec<T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -1305,6 +1313,7 @@ impl<T> ops::IndexMut<ops::RangeFrom<uint>> for Vec<T> {
|
||||
self.as_mut_slice().index_mut(index)
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::IndexMut<ops::FullRange> for Vec<T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -1313,7 +1322,6 @@ impl<T> ops::IndexMut<ops::FullRange> for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Deref for Vec<T> {
|
||||
type Target = [T];
|
||||
@ -1494,10 +1502,10 @@ impl<T> Default for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collections", reason = "waiting on Show stability")]
|
||||
impl<T: fmt::Show> fmt::Show for Vec<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Debug> fmt::Debug for Vec<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Show::fmt(self.as_slice(), f)
|
||||
fmt::Debug::fmt(self.as_slice(), f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2168,7 +2176,7 @@ mod tests {
|
||||
#[should_fail]
|
||||
fn test_slice_out_of_bounds_1() {
|
||||
let x: Vec<int> = vec![1, 2, 3, 4, 5];
|
||||
&x[(-1)..];
|
||||
&x[-1..];
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -2182,7 +2190,7 @@ mod tests {
|
||||
#[should_fail]
|
||||
fn test_slice_out_of_bounds_3() {
|
||||
let x: Vec<int> = vec![1, 2, 3, 4, 5];
|
||||
&x[(-1)..4];
|
||||
&x[-1..4];
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -514,7 +514,7 @@ impl<V: Ord> Ord for VecMap<V> {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<V: fmt::Show> fmt::Show for VecMap<V> {
|
||||
impl<V: fmt::Debug> fmt::Debug for VecMap<V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "VecMap {{"));
|
||||
|
||||
@ -991,7 +991,7 @@ mod test_map {
|
||||
map.insert(3, 4i);
|
||||
|
||||
let map_str = format!("{:?}", map);
|
||||
assert!(map_str == "VecMap {1: 2i, 3: 4i}" || map_str == "{3: 4i, 1: 2i}");
|
||||
assert!(map_str == "VecMap {1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}");
|
||||
assert_eq!(format!("{:?}", empty), "VecMap {}");
|
||||
}
|
||||
|
||||
|
@ -34,11 +34,11 @@
|
||||
//! use runtime reflection instead.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use std::fmt::Show;
|
||||
//! use std::fmt::Debug;
|
||||
//! use std::any::Any;
|
||||
//!
|
||||
//! // Logger function for any type that implements Show.
|
||||
//! fn log<T: Any+Show>(value: &T) {
|
||||
//! // Logger function for any type that implements Debug.
|
||||
//! fn log<T: Any + Debug>(value: &T) {
|
||||
//! let value_any = value as &Any;
|
||||
//!
|
||||
//! // try to convert our value to a String. If successful, we want to
|
||||
@ -55,7 +55,7 @@
|
||||
//! }
|
||||
//!
|
||||
//! // This function wants to log its parameter out prior to doing work with it.
|
||||
//! fn do_work<T: Show+'static>(value: &T) {
|
||||
//! fn do_work<T: Debug + 'static>(value: &T) {
|
||||
//! log(value);
|
||||
//! // ...do some other work
|
||||
//! }
|
||||
@ -75,7 +75,7 @@ use mem::transmute;
|
||||
use option::Option::{self, Some, None};
|
||||
use raw::TraitObject;
|
||||
use intrinsics;
|
||||
#[cfg(not(stage0))] use marker::Sized;
|
||||
use marker::Sized;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Any trait
|
||||
@ -176,7 +176,6 @@ pub struct TypeId {
|
||||
impl TypeId {
|
||||
/// Returns the `TypeId` of the type this generic function has been
|
||||
/// instantiated with
|
||||
#[cfg(not(stage0))]
|
||||
#[unstable(feature = "core",
|
||||
reason = "may grow a `Reflect` bound soon via marker traits")]
|
||||
pub fn of<T: ?Sized + 'static>() -> TypeId {
|
||||
@ -184,10 +183,4 @@ impl TypeId {
|
||||
t: unsafe { intrinsics::type_id::<T>() },
|
||||
}
|
||||
}
|
||||
|
||||
/// dox
|
||||
#[cfg(stage0)]
|
||||
pub fn of<T: 'static>() -> TypeId {
|
||||
unsafe { intrinsics::type_id::<T>() }
|
||||
}
|
||||
}
|
||||
|
@ -39,11 +39,10 @@ macro_rules! array_impls {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "core",
|
||||
reason = "waiting for Show to stabilize")]
|
||||
impl<T:fmt::Show> fmt::Show for [T; $N] {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Debug> fmt::Debug for [T; $N] {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Show::fmt(&&self[], f)
|
||||
fmt::Debug::fmt(&&self[], f)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,6 @@ impl<T> ToOwned<T> for T where T: Clone {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Show)]
|
||||
pub enum Cow<'a, T, B: ?Sized + 'a> where B: ToOwned<T> {
|
||||
/// Borrowed data.
|
||||
Borrowed(&'a B),
|
||||
@ -240,14 +239,27 @@ impl<'a, T, B: ?Sized> PartialOrd for Cow<'a, T, B> where B: PartialOrd + ToOwne
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T, B: ?Sized> fmt::String for Cow<'a, T, B> where
|
||||
B: fmt::String + ToOwned<T>,
|
||||
T: fmt::String,
|
||||
impl<'a, T, B: ?Sized> fmt::Debug for Cow<'a, T, B> where
|
||||
B: fmt::Debug + ToOwned<T>,
|
||||
T: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Borrowed(ref b) => fmt::String::fmt(b, f),
|
||||
Owned(ref o) => fmt::String::fmt(o, f),
|
||||
Borrowed(ref b) => fmt::Debug::fmt(b, f),
|
||||
Owned(ref o) => fmt::Debug::fmt(o, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T, B: ?Sized> fmt::Display for Cow<'a, T, B> where
|
||||
B: fmt::Display + ToOwned<T>,
|
||||
T: fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Borrowed(ref b) => fmt::Display::fmt(b, f),
|
||||
Owned(ref o) => fmt::Display::fmt(o, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +74,10 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Note that this example uses `Rc<T>` and not `Arc<T>`. `RefCell<T>`s are for single-threaded
|
||||
//! scenarios. Consider using `Mutex<T>` if you need shared mutability in a multi-threaded
|
||||
//! situation.
|
||||
//!
|
||||
//! ## Implementation details of logically-immutable methods
|
||||
//!
|
||||
//! Occasionally it may be desirable not to expose in an API that
|
||||
|
@ -14,14 +14,15 @@
|
||||
//!
|
||||
//! `Error` is a trait representing the basic expectations for error values,
|
||||
//! i.e. values of type `E` in `Result<T, E>`. At a minimum, errors must provide
|
||||
//! a description, but they may optionally provide additional detail and cause
|
||||
//! chain information:
|
||||
//! a description, but they may optionally provide additional detail (via
|
||||
//! `Display`) and cause chain information:
|
||||
//!
|
||||
//! ```
|
||||
//! trait Error {
|
||||
//! use std::fmt::Display;
|
||||
//!
|
||||
//! trait Error: Display {
|
||||
//! fn description(&self) -> &str;
|
||||
//!
|
||||
//! fn detail(&self) -> Option<String> { None }
|
||||
//! fn cause(&self) -> Option<&Error> { None }
|
||||
//! }
|
||||
//! ```
|
||||
@ -80,21 +81,16 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use prelude::v1::*;
|
||||
|
||||
use str::Utf8Error;
|
||||
use string::{FromUtf8Error, FromUtf16Error};
|
||||
use prelude::*;
|
||||
use fmt::Display;
|
||||
|
||||
/// Base functionality for all errors in Rust.
|
||||
#[unstable(feature = "std_misc",
|
||||
#[unstable(feature = "core",
|
||||
reason = "the exact API of this trait may change")]
|
||||
pub trait Error {
|
||||
pub trait Error: Display {
|
||||
/// A short description of the error; usually a static string.
|
||||
fn description(&self) -> &str;
|
||||
|
||||
/// A detailed description of the error, usually including dynamic information.
|
||||
fn detail(&self) -> Option<String> { None }
|
||||
|
||||
/// The lower-level cause of this error, if any.
|
||||
fn cause(&self) -> Option<&Error> { None }
|
||||
}
|
||||
@ -114,26 +110,3 @@ impl<E> FromError<E> for E {
|
||||
err
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Error for Utf8Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Utf8Error::TooShort => "invalid utf-8: not enough bytes",
|
||||
Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents",
|
||||
}
|
||||
}
|
||||
|
||||
fn detail(&self) -> Option<String> { Some(self.to_string()) }
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Error for FromUtf8Error {
|
||||
fn description(&self) -> &str { "invalid utf-8" }
|
||||
fn detail(&self) -> Option<String> { Some(self.to_string()) }
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Error for FromUtf16Error {
|
||||
fn description(&self) -> &str { "invalid utf-16" }
|
||||
}
|
@ -179,7 +179,7 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
|
||||
_ => ()
|
||||
}
|
||||
|
||||
buf.slice_to_mut(end).reverse();
|
||||
buf[..end].reverse();
|
||||
|
||||
// Remember start of the fractional digits.
|
||||
// Points one beyond end of buf if none get generated,
|
||||
@ -316,7 +316,7 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
|
||||
|
||||
impl<'a> fmt::Writer for Filler<'a> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
slice::bytes::copy_memory(self.buf.slice_from_mut(*self.end),
|
||||
slice::bytes::copy_memory(&mut self.buf[(*self.end)..],
|
||||
s.as_bytes());
|
||||
*self.end += s.len();
|
||||
Ok(())
|
||||
|
@ -26,12 +26,15 @@ use ops::{Deref, FnOnce};
|
||||
use result;
|
||||
use slice::SliceExt;
|
||||
use slice;
|
||||
use str::{self, StrExt, Utf8Error};
|
||||
use str::{self, StrExt};
|
||||
|
||||
pub use self::num::radix;
|
||||
pub use self::num::Radix;
|
||||
pub use self::num::RadixFmt;
|
||||
|
||||
#[cfg(stage0)] pub use self::Debug as Show;
|
||||
#[cfg(stage0)] pub use self::Display as String;
|
||||
|
||||
mod num;
|
||||
mod float;
|
||||
pub mod rt;
|
||||
@ -48,7 +51,7 @@ pub type Result = result::Result<(), Error>;
|
||||
/// some other means.
|
||||
#[unstable(feature = "core",
|
||||
reason = "core and I/O reconciliation may alter this definition")]
|
||||
#[derive(Copy)]
|
||||
#[derive(Copy, Show)]
|
||||
pub struct Error;
|
||||
|
||||
/// A collection of methods that are required to format a message into a stream.
|
||||
@ -138,7 +141,7 @@ pub struct Argument<'a> {
|
||||
impl<'a> Argument<'a> {
|
||||
#[inline(never)]
|
||||
fn show_uint(x: &uint, f: &mut Formatter) -> Result {
|
||||
Show::fmt(x, f)
|
||||
Display::fmt(x, f)
|
||||
}
|
||||
|
||||
fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter) -> Result) -> Argument<'b> {
|
||||
@ -221,14 +224,15 @@ pub struct Arguments<'a> {
|
||||
args: &'a [Argument<'a>],
|
||||
}
|
||||
|
||||
impl<'a> Show for Arguments<'a> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> Debug for Arguments<'a> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
||||
String::fmt(self, fmt)
|
||||
Display::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> String for Arguments<'a> {
|
||||
impl<'a> Display for Arguments<'a> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
||||
write(fmt.buf, *self)
|
||||
}
|
||||
@ -238,20 +242,52 @@ impl<'a> String for Arguments<'a> {
|
||||
/// should implement this.
|
||||
#[unstable(feature = "core",
|
||||
reason = "I/O and core have yet to be reconciled")]
|
||||
#[deprecated(since = "1.0.0", reason = "renamed to Debug")]
|
||||
#[cfg(not(stage0))]
|
||||
pub trait Show {
|
||||
/// Formats the value using the given formatter.
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
/// Format trait for the `:?` format. Useful for debugging, most all types
|
||||
/// should implement this.
|
||||
#[unstable(feature = "core",
|
||||
reason = "I/O and core have yet to be reconciled")]
|
||||
pub trait Debug {
|
||||
/// Formats the value using the given formatter.
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: Show + ?Sized> Debug for T {
|
||||
#[allow(deprecated)]
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { Show::fmt(self, f) }
|
||||
}
|
||||
|
||||
/// When a value can be semantically expressed as a String, this trait may be
|
||||
/// used. It corresponds to the default format, `{}`.
|
||||
#[unstable(feature = "core")]
|
||||
#[deprecated(since = "1.0.0", reason = "renamed to Display")]
|
||||
#[cfg(not(stage0))]
|
||||
pub trait String {
|
||||
/// Formats the value using the given formatter.
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
/// When a value can be semantically expressed as a String, this trait may be
|
||||
/// used. It corresponds to the default format, `{}`.
|
||||
#[unstable(feature = "core",
|
||||
reason = "I/O and core have yet to be reconciled")]
|
||||
pub trait String {
|
||||
pub trait Display {
|
||||
/// Formats the value using the given formatter.
|
||||
fn fmt(&self, &mut Formatter) -> Result;
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: String + ?Sized> Display for T {
|
||||
#[allow(deprecated)]
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { String::fmt(self, f) }
|
||||
}
|
||||
|
||||
/// Format trait for the `o` character
|
||||
#[unstable(feature = "core",
|
||||
@ -605,9 +641,10 @@ impl<'a> Formatter<'a> {
|
||||
pub fn precision(&self) -> Option<uint> { self.precision }
|
||||
}
|
||||
|
||||
impl Show for Error {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
String::fmt("an error occurred when formatting an argument", f)
|
||||
Display::fmt("an error occurred when formatting an argument", f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -635,9 +672,11 @@ pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
|
||||
macro_rules! fmt_refs {
|
||||
($($tr:ident),*) => {
|
||||
$(
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T: ?Sized + $tr> $tr for &'a T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { $tr::fmt(&**self, f) }
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T: ?Sized + $tr> $tr for &'a mut T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { $tr::fmt(&**self, f) }
|
||||
}
|
||||
@ -645,22 +684,24 @@ macro_rules! fmt_refs {
|
||||
}
|
||||
}
|
||||
|
||||
fmt_refs! { Show, String, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
|
||||
fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
|
||||
|
||||
impl Show for bool {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Debug for bool {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
String::fmt(self, f)
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl String for bool {
|
||||
impl Display for bool {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
String::fmt(if *self { "true" } else { "false" }, f)
|
||||
Display::fmt(if *self { "true" } else { "false" }, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Show for str {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Debug for str {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
try!(write!(f, "\""));
|
||||
for c in self.chars().flat_map(|c| c.escape_default()) {
|
||||
@ -671,13 +712,14 @@ impl Show for str {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl String for str {
|
||||
impl Display for str {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
f.pad(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Show for char {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Debug for char {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
use char::CharExt;
|
||||
try!(write!(f, "'"));
|
||||
@ -689,15 +731,16 @@ impl Show for char {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl String for char {
|
||||
impl Display for char {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
let mut utf8 = [0u8; 4];
|
||||
let amt = self.encode_utf8(&mut utf8).unwrap_or(0);
|
||||
let s: &str = unsafe { mem::transmute(&utf8[..amt]) };
|
||||
String::fmt(s, f)
|
||||
Display::fmt(s, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Pointer for *const T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
f.flags |= 1 << (rt::FlagAlternate as uint);
|
||||
@ -707,18 +750,21 @@ impl<T> Pointer for *const T {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Pointer for *mut T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
Pointer::fmt(&(*self as *const T), f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Pointer for &'a T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
Pointer::fmt(&(*self as *const T), f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Pointer for &'a mut T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
Pointer::fmt(&(&**self as *const T), f)
|
||||
@ -727,15 +773,15 @@ impl<'a, T> Pointer for &'a mut T {
|
||||
|
||||
macro_rules! floating { ($ty:ident) => {
|
||||
|
||||
impl Show for $ty {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Debug for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
||||
try!(String::fmt(self, fmt));
|
||||
fmt.write_str(stringify!($ty))
|
||||
Display::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl String for $ty {
|
||||
impl Display for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
||||
use num::Float;
|
||||
|
||||
@ -756,6 +802,7 @@ macro_rules! floating { ($ty:ident) => {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl LowerExp for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
||||
use num::Float;
|
||||
@ -777,6 +824,7 @@ macro_rules! floating { ($ty:ident) => {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl UpperExp for $ty {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result {
|
||||
use num::Float;
|
||||
@ -801,12 +849,14 @@ macro_rules! floating { ($ty:ident) => {
|
||||
floating! { f32 }
|
||||
floating! { f64 }
|
||||
|
||||
// Implementation of Show for various core types
|
||||
// Implementation of Display/Debug for various core types
|
||||
|
||||
impl<T> Show for *const T {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Debug for *const T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) }
|
||||
}
|
||||
impl<T> Show for *mut T {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Debug for *mut T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) }
|
||||
}
|
||||
|
||||
@ -817,7 +867,8 @@ macro_rules! peel {
|
||||
macro_rules! tuple {
|
||||
() => ();
|
||||
( $($name:ident,)+ ) => (
|
||||
impl<$($name:Show),*> Show for ($($name,)*) {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<$($name:Debug),*> Debug for ($($name,)*) {
|
||||
#[allow(non_snake_case, unused_assignments)]
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
try!(write!(f, "("));
|
||||
@ -842,11 +893,13 @@ macro_rules! tuple {
|
||||
|
||||
tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
|
||||
|
||||
impl<'a> Show for &'a (any::Any+'a) {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> Debug for &'a (any::Any+'a) {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") }
|
||||
}
|
||||
|
||||
impl<T: Show> Show for [T] {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Debug> Debug for [T] {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
|
||||
try!(write!(f, "["));
|
||||
@ -867,20 +920,22 @@ impl<T: Show> Show for [T] {
|
||||
}
|
||||
}
|
||||
|
||||
impl Show for () {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Debug for () {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
f.pad("()")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Show> Show for Cell<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Copy + Debug> Debug for Cell<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
write!(f, "Cell {{ value: {:?} }}", self.get())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "core")]
|
||||
impl<T: Show> Show for RefCell<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Debug> Debug for RefCell<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
match self.try_borrow() {
|
||||
Some(val) => write!(f, "RefCell {{ value: {:?} }}", val),
|
||||
@ -889,29 +944,17 @@ impl<T: Show> Show for RefCell<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T: Show> Show for Ref<'b, T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'b, T: Debug> Debug for Ref<'b, T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
Show::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T: Show> Show for RefMut<'b, T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
Show::fmt(&*(self.deref()), f)
|
||||
Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl String for Utf8Error {
|
||||
impl<'b, T: Debug> Debug for RefMut<'b, T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
match *self {
|
||||
Utf8Error::InvalidByte(n) => {
|
||||
write!(f, "invalid utf-8: invalid byte at index {}", n)
|
||||
}
|
||||
Utf8Error::TooShort => {
|
||||
write!(f, "invalid utf-8: byte slice too short")
|
||||
}
|
||||
}
|
||||
Debug::fmt(&*(self.deref()), f)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,13 +157,14 @@ pub fn radix<T>(x: T, base: u8) -> RadixFmt<T, Radix> {
|
||||
|
||||
macro_rules! radix_fmt {
|
||||
($T:ty as $U:ty, $fmt:ident, $S:expr) => {
|
||||
impl fmt::Show for RadixFmt<$T, Radix> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Debug for RadixFmt<$T, Radix> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(fmt::String::fmt(self, f));
|
||||
f.write_str($S)
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
impl fmt::String for RadixFmt<$T, Radix> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for RadixFmt<$T, Radix> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self { RadixFmt(ref x, radix) => radix.$fmt(*x as $U, f) }
|
||||
}
|
||||
@ -172,6 +173,7 @@ macro_rules! radix_fmt {
|
||||
}
|
||||
macro_rules! int_base {
|
||||
($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::$Trait for $T {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
$Radix.fmt_int(*self as $U, f)
|
||||
@ -182,10 +184,10 @@ macro_rules! int_base {
|
||||
|
||||
macro_rules! show {
|
||||
($T:ident with $S:expr) => {
|
||||
impl fmt::Show for $T {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Debug for $T {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(fmt::String::fmt(self, f));
|
||||
f.write_str($S)
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -195,7 +197,7 @@ macro_rules! integer {
|
||||
integer! { $Int, $Uint, stringify!($Int), stringify!($Uint) }
|
||||
};
|
||||
($Int:ident, $Uint:ident, $SI:expr, $SU:expr) => {
|
||||
int_base! { String for $Int as $Int -> Decimal }
|
||||
int_base! { Display for $Int as $Int -> Decimal }
|
||||
int_base! { Binary for $Int as $Uint -> Binary }
|
||||
int_base! { Octal for $Int as $Uint -> Octal }
|
||||
int_base! { LowerHex for $Int as $Uint -> LowerHex }
|
||||
@ -203,7 +205,7 @@ macro_rules! integer {
|
||||
radix_fmt! { $Int as $Int, fmt_int, $SI }
|
||||
show! { $Int with $SI }
|
||||
|
||||
int_base! { String for $Uint as $Uint -> Decimal }
|
||||
int_base! { Display for $Uint as $Uint -> Decimal }
|
||||
int_base! { Binary for $Uint as $Uint -> Binary }
|
||||
int_base! { Octal for $Uint as $Uint -> Octal }
|
||||
int_base! { LowerHex for $Uint as $Uint -> LowerHex }
|
||||
|
@ -44,8 +44,6 @@
|
||||
|
||||
use marker::Sized;
|
||||
|
||||
#[cfg(stage0)] use any::TypeId;
|
||||
|
||||
pub type GlueFn = extern "Rust" fn(*const i8);
|
||||
|
||||
#[lang="ty_desc"]
|
||||
@ -208,12 +206,8 @@ extern "rust-intrinsic" {
|
||||
/// Gets an identifier which is globally unique to the specified type. This
|
||||
/// function will return the same value for a type regardless of whichever
|
||||
/// crate it is invoked in.
|
||||
#[cfg(not(stage0))]
|
||||
pub fn type_id<T: ?Sized + 'static>() -> u64;
|
||||
|
||||
#[cfg(stage0)]
|
||||
pub fn type_id<T: ?Sized + 'static>() -> TypeId;
|
||||
|
||||
/// Create a value initialized to zero.
|
||||
///
|
||||
/// `init` is unsafe because it returns a zeroed-out datum,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -64,6 +64,8 @@
|
||||
#![feature(unboxed_closures)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![feature(on_unimplemented)]
|
||||
// FIXME(#21363) remove `old_impl_check` when bug is fixed
|
||||
#![feature(old_impl_check)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[macro_use]
|
||||
@ -137,6 +139,7 @@ pub mod slice;
|
||||
pub mod str;
|
||||
pub mod hash;
|
||||
pub mod fmt;
|
||||
pub mod error;
|
||||
|
||||
// note: does not need to be public
|
||||
mod tuple;
|
||||
|
@ -386,17 +386,6 @@ pub struct ContravariantLifetime<'a>;
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct InvariantLifetime<'a>;
|
||||
|
||||
/// A type which is considered "not sendable", meaning that it cannot
|
||||
/// be safely sent between tasks, even if it is owned. This is
|
||||
/// typically embedded in other types, such as `Gc`, to ensure that
|
||||
/// their instances remain thread-local.
|
||||
#[unstable(feature = "core",
|
||||
reason = "likely to change with new variance strategy")]
|
||||
#[lang="no_send_bound"]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
pub struct NoSend;
|
||||
|
||||
/// A type which is considered "not POD", meaning that it is not
|
||||
/// implicitly copyable. This is typically embedded in other types to
|
||||
/// ensure that they are never copied, even if they lack a destructor.
|
||||
@ -407,16 +396,6 @@ pub struct NoSend;
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct NoCopy;
|
||||
|
||||
/// A type which is considered "not sync", meaning that
|
||||
/// its contents are not threadsafe, hence they cannot be
|
||||
/// shared between tasks.
|
||||
#[unstable(feature = "core",
|
||||
reason = "likely to change with new variance strategy")]
|
||||
#[lang="no_sync_bound"]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[cfg(stage0)] // NOTE remove impl after next snapshot
|
||||
pub struct NoSync;
|
||||
|
||||
/// A type which is considered managed by the GC. This is typically
|
||||
/// embedded in other types.
|
||||
#[unstable(feature = "core",
|
||||
|
@ -33,8 +33,6 @@
|
||||
//! demonstrates adding and subtracting two `Point`s.
|
||||
//!
|
||||
//! ```rust
|
||||
//! #![feature(associated_types)]
|
||||
//!
|
||||
//! use std::ops::{Add, Sub};
|
||||
//!
|
||||
//! #[derive(Show)]
|
||||
@ -69,10 +67,7 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use clone::Clone;
|
||||
use iter::{Step, Iterator,DoubleEndedIterator,ExactSizeIterator};
|
||||
use marker::Sized;
|
||||
use option::Option::{self, Some, None};
|
||||
use fmt;
|
||||
|
||||
/// The `Drop` trait is used to run some code when a value goes out of scope. This
|
||||
@ -168,8 +163,6 @@ macro_rules! forward_ref_binop {
|
||||
/// calling `add`, and therefore, `main` prints `Adding!`.
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::Add;
|
||||
///
|
||||
/// #[derive(Copy)]
|
||||
@ -223,8 +216,6 @@ add_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64 }
|
||||
/// calling `sub`, and therefore, `main` prints `Subtracting!`.
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::Sub;
|
||||
///
|
||||
/// #[derive(Copy)]
|
||||
@ -278,8 +269,6 @@ sub_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64 }
|
||||
/// calling `mul`, and therefore, `main` prints `Multiplying!`.
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::Mul;
|
||||
///
|
||||
/// #[derive(Copy)]
|
||||
@ -333,8 +322,6 @@ mul_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64 }
|
||||
/// calling `div`, and therefore, `main` prints `Dividing!`.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::Div;
|
||||
///
|
||||
/// #[derive(Copy)]
|
||||
@ -388,8 +375,6 @@ div_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64 }
|
||||
/// calling `rem`, and therefore, `main` prints `Remainder-ing!`.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::Rem;
|
||||
///
|
||||
/// #[derive(Copy)]
|
||||
@ -462,8 +447,6 @@ rem_float_impl! { f64, fmod }
|
||||
/// `neg`, and therefore, `main` prints `Negating!`.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::Neg;
|
||||
///
|
||||
/// struct Foo;
|
||||
@ -541,8 +524,6 @@ neg_uint_impl! { u64, i64 }
|
||||
/// `not`, and therefore, `main` prints `Not-ing!`.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::Not;
|
||||
///
|
||||
/// struct Foo;
|
||||
@ -597,8 +578,6 @@ not_impl! { bool uint u8 u16 u32 u64 int i8 i16 i32 i64 }
|
||||
/// calling `bitand`, and therefore, `main` prints `Bitwise And-ing!`.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::BitAnd;
|
||||
///
|
||||
/// #[derive(Copy)]
|
||||
@ -652,8 +631,6 @@ bitand_impl! { bool uint u8 u16 u32 u64 int i8 i16 i32 i64 }
|
||||
/// calling `bitor`, and therefore, `main` prints `Bitwise Or-ing!`.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::BitOr;
|
||||
///
|
||||
/// #[derive(Copy)]
|
||||
@ -707,8 +684,6 @@ bitor_impl! { bool uint u8 u16 u32 u64 int i8 i16 i32 i64 }
|
||||
/// calling `bitxor`, and therefore, `main` prints `Bitwise Xor-ing!`.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::BitXor;
|
||||
///
|
||||
/// #[derive(Copy)]
|
||||
@ -762,8 +737,6 @@ bitxor_impl! { bool uint u8 u16 u32 u64 int i8 i16 i32 i64 }
|
||||
/// calling `shl`, and therefore, `main` prints `Shifting left!`.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::Shl;
|
||||
///
|
||||
/// #[derive(Copy)]
|
||||
@ -835,8 +808,6 @@ shl_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
|
||||
/// calling `shr`, and therefore, `main` prints `Shifting right!`.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::Shr;
|
||||
///
|
||||
/// #[derive(Copy)]
|
||||
@ -928,10 +899,12 @@ shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
|
||||
/// }
|
||||
/// ```
|
||||
#[lang="index"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Index<Index: ?Sized> {
|
||||
type Output: ?Sized;
|
||||
|
||||
/// The method for the indexing (`Foo[Bar]`) operation
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn index<'a>(&'a self, index: &Index) -> &'a Self::Output;
|
||||
}
|
||||
|
||||
@ -964,30 +937,32 @@ pub trait Index<Index: ?Sized> {
|
||||
/// }
|
||||
/// ```
|
||||
#[lang="index_mut"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait IndexMut<Index: ?Sized> {
|
||||
type Output: ?Sized;
|
||||
|
||||
/// The method for the indexing (`Foo[Bar]`) operation
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn index_mut<'a>(&'a mut self, index: &Index) -> &'a mut Self::Output;
|
||||
}
|
||||
|
||||
/// An unbounded range.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[lang="full_range"]
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
#[unstable(feature = "core", reason = "may be renamed to RangeFull")]
|
||||
pub struct FullRange;
|
||||
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
impl fmt::Show for FullRange {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Debug for FullRange {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Show::fmt("..", fmt)
|
||||
fmt::Debug::fmt("..", fmt)
|
||||
}
|
||||
}
|
||||
|
||||
/// A (half-open) range which is bounded at both ends.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[lang="range"]
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Range<Idx> {
|
||||
/// The lower bound of the range (inclusive).
|
||||
pub start: Idx,
|
||||
@ -995,49 +970,8 @@ pub struct Range<Idx> {
|
||||
pub end: Idx,
|
||||
}
|
||||
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
impl<Idx: Clone + Step> Iterator for Range<Idx> {
|
||||
type Item = Idx;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Idx> {
|
||||
if self.start < self.end {
|
||||
let result = self.start.clone();
|
||||
self.start.step();
|
||||
return Some(result);
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (uint, Option<uint>) {
|
||||
if let Some(hint) = Step::steps_between(&self.start, &self.end) {
|
||||
(hint, Some(hint))
|
||||
} else {
|
||||
(0, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
impl<Idx: Clone + Step> DoubleEndedIterator for Range<Idx> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<Idx> {
|
||||
if self.start < self.end {
|
||||
self.end.step_back();
|
||||
return Some(self.end.clone());
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
impl<Idx: Clone + Step> ExactSizeIterator for Range<Idx> {}
|
||||
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
impl<Idx: fmt::Show> fmt::Show for Range<Idx> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "{:?}..{:?}", self.start, self.end)
|
||||
}
|
||||
@ -1046,27 +980,16 @@ impl<Idx: fmt::Show> fmt::Show for Range<Idx> {
|
||||
/// A range which is only bounded below.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[lang="range_from"]
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct RangeFrom<Idx> {
|
||||
/// The lower bound of the range (inclusive).
|
||||
pub start: Idx,
|
||||
}
|
||||
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
impl<Idx: Clone + Step> Iterator for RangeFrom<Idx> {
|
||||
type Item = Idx;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Idx> {
|
||||
// Deliberately overflow so we loop forever.
|
||||
let result = self.start.clone();
|
||||
self.start.step();
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
impl<Idx: fmt::Show> fmt::Show for RangeFrom<Idx> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "{:?}..", self.start)
|
||||
}
|
||||
@ -1075,14 +998,14 @@ impl<Idx: fmt::Show> fmt::Show for RangeFrom<Idx> {
|
||||
/// A range which is only bounded above.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[lang="range_to"]
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct RangeTo<Idx> {
|
||||
/// The upper bound of the range (exclusive).
|
||||
pub end: Idx,
|
||||
}
|
||||
|
||||
#[unstable(feature = "core", reason = "API still in development")]
|
||||
impl<Idx: fmt::Show> fmt::Show for RangeTo<Idx> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<Idx: fmt::Debug> fmt::Debug for RangeTo<Idx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "..{:?}", self.end)
|
||||
}
|
||||
@ -1098,8 +1021,6 @@ impl<Idx: fmt::Show> fmt::Show for RangeTo<Idx> {
|
||||
/// struct.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::Deref;
|
||||
///
|
||||
/// struct DerefExample<T> {
|
||||
@ -1153,8 +1074,6 @@ impl<'a, T: ?Sized> Deref for &'a mut T {
|
||||
/// struct.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(associated_types)]
|
||||
///
|
||||
/// use std::ops::{Deref, DerefMut};
|
||||
///
|
||||
/// struct DerefMutExample<T> {
|
||||
|
@ -229,7 +229,7 @@
|
||||
use self::Result::{Ok, Err};
|
||||
|
||||
use clone::Clone;
|
||||
use fmt::Show;
|
||||
use fmt::Display;
|
||||
use iter::{Iterator, IteratorExt, DoubleEndedIterator, FromIterator, ExactSizeIterator};
|
||||
use ops::{FnMut, FnOnce};
|
||||
use option::Option::{self, None, Some};
|
||||
@ -715,7 +715,7 @@ impl<T, E> Result<T, E> {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T, E: Show> Result<T, E> {
|
||||
impl<T, E: Display> Result<T, E> {
|
||||
/// Unwraps a result, yielding the content of an `Ok`.
|
||||
///
|
||||
/// # Panics
|
||||
@ -740,13 +740,13 @@ impl<T, E: Show> Result<T, E> {
|
||||
match self {
|
||||
Ok(t) => t,
|
||||
Err(e) =>
|
||||
panic!("called `Result::unwrap()` on an `Err` value: {:?}", e)
|
||||
panic!("called `Result::unwrap()` on an `Err` value: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Show, E> Result<T, E> {
|
||||
impl<T: Display, E> Result<T, E> {
|
||||
/// Unwraps a result, yielding the content of an `Err`.
|
||||
///
|
||||
/// # Panics
|
||||
@ -770,7 +770,7 @@ impl<T: Show, E> Result<T, E> {
|
||||
pub fn unwrap_err(self) -> E {
|
||||
match self {
|
||||
Ok(t) =>
|
||||
panic!("called `Result::unwrap_err()` on an `Ok` value: {:?}", t),
|
||||
panic!("called `Result::unwrap_err()` on an `Ok` value: {}", t),
|
||||
Err(e) => e
|
||||
}
|
||||
}
|
||||
|
@ -67,9 +67,6 @@ use raw::Slice as RawSlice;
|
||||
pub trait SliceExt {
|
||||
type Item;
|
||||
|
||||
fn slice<'a>(&'a self, start: uint, end: uint) -> &'a [Self::Item];
|
||||
fn slice_from<'a>(&'a self, start: uint) -> &'a [Self::Item];
|
||||
fn slice_to<'a>(&'a self, end: uint) -> &'a [Self::Item];
|
||||
fn split_at<'a>(&'a self, mid: uint) -> (&'a [Self::Item], &'a [Self::Item]);
|
||||
fn iter<'a>(&'a self) -> Iter<'a, Self::Item>;
|
||||
fn split<'a, P>(&'a self, pred: P) -> Split<'a, Self::Item, P>
|
||||
@ -93,9 +90,6 @@ pub trait SliceExt {
|
||||
fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
fn get_mut<'a>(&'a mut self, index: uint) -> Option<&'a mut Self::Item>;
|
||||
fn as_mut_slice<'a>(&'a mut self) -> &'a mut [Self::Item];
|
||||
fn slice_mut<'a>(&'a mut self, start: uint, end: uint) -> &'a mut [Self::Item];
|
||||
fn slice_from_mut<'a>(&'a mut self, start: uint) -> &'a mut [Self::Item];
|
||||
fn slice_to_mut<'a>(&'a mut self, end: uint) -> &'a mut [Self::Item];
|
||||
fn iter_mut<'a>(&'a mut self) -> IterMut<'a, Self::Item>;
|
||||
fn first_mut<'a>(&'a mut self) -> Option<&'a mut Self::Item>;
|
||||
fn tail_mut<'a>(&'a mut self) -> &'a mut [Self::Item];
|
||||
@ -135,28 +129,6 @@ pub trait SliceExt {
|
||||
impl<T> SliceExt for [T] {
|
||||
type Item = T;
|
||||
|
||||
#[inline]
|
||||
fn slice(&self, start: uint, end: uint) -> &[T] {
|
||||
assert!(start <= end);
|
||||
assert!(end <= self.len());
|
||||
unsafe {
|
||||
transmute(RawSlice {
|
||||
data: self.as_ptr().offset(start as int),
|
||||
len: (end - start)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_from(&self, start: uint) -> &[T] {
|
||||
self.slice(start, self.len())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_to(&self, end: uint) -> &[T] {
|
||||
self.slice(0, end)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn split_at(&self, mid: uint) -> (&[T], &[T]) {
|
||||
(&self[..mid], &self[mid..])
|
||||
@ -240,7 +212,7 @@ impl<T> SliceExt for [T] {
|
||||
|
||||
#[inline]
|
||||
fn init(&self) -> &[T] {
|
||||
&self[..(self.len() - 1)]
|
||||
&self[..self.len() - 1]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -291,20 +263,6 @@ impl<T> SliceExt for [T] {
|
||||
#[inline]
|
||||
fn as_mut_slice(&mut self) -> &mut [T] { self }
|
||||
|
||||
fn slice_mut(&mut self, start: uint, end: uint) -> &mut [T] {
|
||||
ops::IndexMut::index_mut(self, &ops::Range { start: start, end: end } )
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_from_mut(&mut self, start: uint) -> &mut [T] {
|
||||
ops::IndexMut::index_mut(self, &ops::RangeFrom { start: start } )
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_to_mut(&mut self, end: uint) -> &mut [T] {
|
||||
ops::IndexMut::index_mut(self, &ops::RangeTo { end: end } )
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn split_at_mut(&mut self, mid: uint) -> (&mut [T], &mut [T]) {
|
||||
unsafe {
|
||||
@ -345,13 +303,13 @@ impl<T> SliceExt for [T] {
|
||||
|
||||
#[inline]
|
||||
fn tail_mut(&mut self) -> &mut [T] {
|
||||
self.slice_from_mut(1)
|
||||
&mut self[1 ..]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn init_mut(&mut self) -> &mut [T] {
|
||||
let len = self.len();
|
||||
self.slice_to_mut(len-1)
|
||||
&mut self[.. (len - 1)]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -449,7 +407,7 @@ impl<T> SliceExt for [T] {
|
||||
#[inline]
|
||||
fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq {
|
||||
let (m, n) = (self.len(), needle.len());
|
||||
m >= n && needle == &self[(m-n)..]
|
||||
m >= n && needle == &self[m-n..]
|
||||
}
|
||||
|
||||
#[unstable(feature = "core")]
|
||||
@ -483,7 +441,7 @@ impl<T> SliceExt for [T] {
|
||||
self.swap(j, i-1);
|
||||
|
||||
// Step 4: Reverse the (previously) weakly decreasing part
|
||||
self.slice_from_mut(i).reverse();
|
||||
self[i..].reverse();
|
||||
|
||||
true
|
||||
}
|
||||
@ -505,7 +463,7 @@ impl<T> SliceExt for [T] {
|
||||
}
|
||||
|
||||
// Step 2: Reverse the weakly increasing part
|
||||
self.slice_from_mut(i).reverse();
|
||||
self[i..].reverse();
|
||||
|
||||
// Step 3: Find the rightmost element equal to or bigger than the pivot (i-1)
|
||||
let mut j = self.len() - 1;
|
||||
@ -522,8 +480,8 @@ impl<T> SliceExt for [T] {
|
||||
#[inline]
|
||||
fn clone_from_slice(&mut self, src: &[T]) -> uint where T: Clone {
|
||||
let min = cmp::min(self.len(), src.len());
|
||||
let dst = self.slice_to_mut(min);
|
||||
let src = src.slice_to(min);
|
||||
let dst = &mut self[.. min];
|
||||
let src = &src[.. min];
|
||||
for i in range(0, min) {
|
||||
dst[i].clone_from(&src[i]);
|
||||
}
|
||||
@ -531,6 +489,7 @@ impl<T> SliceExt for [T] {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Index<uint> for [T] {
|
||||
type Output = T;
|
||||
|
||||
@ -541,6 +500,7 @@ impl<T> ops::Index<uint> for [T] {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::IndexMut<uint> for [T] {
|
||||
type Output = T;
|
||||
|
||||
@ -551,6 +511,7 @@ impl<T> ops::IndexMut<uint> for [T] {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Index<ops::Range<uint>> for [T] {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -565,6 +526,7 @@ impl<T> ops::Index<ops::Range<uint>> for [T] {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Index<ops::RangeTo<uint>> for [T] {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -572,6 +534,7 @@ impl<T> ops::Index<ops::RangeTo<uint>> for [T] {
|
||||
self.index(&ops::Range{ start: 0, end: index.end })
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Index<ops::RangeFrom<uint>> for [T] {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -579,6 +542,7 @@ impl<T> ops::Index<ops::RangeFrom<uint>> for [T] {
|
||||
self.index(&ops::Range{ start: index.start, end: self.len() })
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Index<ops::FullRange> for [T] {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -587,6 +551,7 @@ impl<T> ops::Index<ops::FullRange> for [T] {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::IndexMut<ops::Range<uint>> for [T] {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -601,6 +566,7 @@ impl<T> ops::IndexMut<ops::Range<uint>> for [T] {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::IndexMut<ops::RangeTo<uint>> for [T] {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -608,6 +574,7 @@ impl<T> ops::IndexMut<ops::RangeTo<uint>> for [T] {
|
||||
self.index_mut(&ops::Range{ start: 0, end: index.end })
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::IndexMut<ops::RangeFrom<uint>> for [T] {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -616,6 +583,7 @@ impl<T> ops::IndexMut<ops::RangeFrom<uint>> for [T] {
|
||||
self.index_mut(&ops::Range{ start: index.start, end: len })
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::IndexMut<ops::FullRange> for [T] {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -974,7 +942,7 @@ impl<'a, T, P> Iterator for Split<'a, T, P> where P: FnMut(&T) -> bool {
|
||||
None => self.finish(),
|
||||
Some(idx) => {
|
||||
let ret = Some(&self.v[..idx]);
|
||||
self.v = &self.v[(idx + 1)..];
|
||||
self.v = &self.v[idx + 1..];
|
||||
ret
|
||||
}
|
||||
}
|
||||
@ -999,7 +967,7 @@ impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P> where P: FnMut(&T) -> boo
|
||||
match self.v.iter().rposition(|x| (self.pred)(x)) {
|
||||
None => self.finish(),
|
||||
Some(idx) => {
|
||||
let ret = Some(&self.v[(idx + 1)..]);
|
||||
let ret = Some(&self.v[idx + 1..]);
|
||||
self.v = &self.v[..idx];
|
||||
ret
|
||||
}
|
||||
@ -1052,7 +1020,7 @@ impl<'a, T, P> Iterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {
|
||||
Some(idx) => {
|
||||
let tmp = mem::replace(&mut self.v, &mut []);
|
||||
let (head, tail) = tmp.split_at_mut(idx);
|
||||
self.v = tail.slice_from_mut(1);
|
||||
self.v = &mut tail[1..];
|
||||
Some(head)
|
||||
}
|
||||
}
|
||||
@ -1088,7 +1056,7 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where
|
||||
let tmp = mem::replace(&mut self.v, &mut []);
|
||||
let (head, tail) = tmp.split_at_mut(idx);
|
||||
self.v = head;
|
||||
Some(tail.slice_from_mut(1))
|
||||
Some(&mut tail[1..])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1270,6 +1238,9 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> ExactSizeIterator for Chunks<'a, T> {}
|
||||
|
||||
#[unstable(feature = "core", reason = "trait is experimental")]
|
||||
impl<'a, T> RandomAccessIterator for Chunks<'a, T> {
|
||||
#[inline]
|
||||
@ -1348,6 +1319,8 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {}
|
||||
|
||||
//
|
||||
// Free functions
|
||||
|
@ -20,8 +20,10 @@ use self::Searcher::{Naive, TwoWay, TwoWayLong};
|
||||
|
||||
use cmp::{self, Eq};
|
||||
use default::Default;
|
||||
use iter::range;
|
||||
use error::Error;
|
||||
use fmt;
|
||||
use iter::ExactSizeIterator;
|
||||
use iter::range;
|
||||
use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator};
|
||||
use marker::Sized;
|
||||
use mem;
|
||||
@ -247,6 +249,30 @@ impl<'a> CharEq for &'a [char] {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Error for Utf8Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Utf8Error::TooShort => "invalid utf-8: not enough bytes",
|
||||
Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for Utf8Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Utf8Error::InvalidByte(n) => {
|
||||
write!(f, "invalid utf-8: invalid byte at index {}", n)
|
||||
}
|
||||
Utf8Error::TooShort => {
|
||||
write!(f, "invalid utf-8: byte slice too short")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Section: Iterators
|
||||
*/
|
||||
@ -907,13 +933,13 @@ impl<'a> Iterator for SplitStr<'a> {
|
||||
|
||||
match self.it.next() {
|
||||
Some((from, to)) => {
|
||||
let ret = Some(self.it.haystack.slice(self.last_end, from));
|
||||
let ret = Some(&self.it.haystack[self.last_end .. from]);
|
||||
self.last_end = to;
|
||||
ret
|
||||
}
|
||||
None => {
|
||||
self.finished = true;
|
||||
Some(self.it.haystack.slice(self.last_end, self.it.haystack.len()))
|
||||
Some(&self.it.haystack[self.last_end .. self.it.haystack.len()])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1121,27 +1147,90 @@ mod traits {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a slice of the given string from the byte range
|
||||
/// [`begin`..`end`).
|
||||
///
|
||||
/// This operation is `O(1)`.
|
||||
///
|
||||
/// Panics when `begin` and `end` do not point to valid characters
|
||||
/// or point beyond the last character of the string.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let s = "Löwe 老虎 Léopard";
|
||||
/// assert_eq!(&s[0 .. 1], "L");
|
||||
///
|
||||
/// assert_eq!(&s[1 .. 9], "öwe 老");
|
||||
///
|
||||
/// // these will panic:
|
||||
/// // byte 2 lies within `ö`:
|
||||
/// // &s[2 ..3];
|
||||
///
|
||||
/// // byte 8 lies within `老`
|
||||
/// // &s[1 .. 8];
|
||||
///
|
||||
/// // byte 100 is outside the string
|
||||
/// // &s[3 .. 100];
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ops::Index<ops::Range<uint>> for str {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn index(&self, index: &ops::Range<uint>) -> &str {
|
||||
self.slice(index.start, index.end)
|
||||
// is_char_boundary checks that the index is in [0, .len()]
|
||||
if index.start <= index.end &&
|
||||
self.is_char_boundary(index.start) &&
|
||||
self.is_char_boundary(index.end) {
|
||||
unsafe { self.slice_unchecked(index.start, index.end) }
|
||||
} else {
|
||||
super::slice_error_fail(self, index.start, index.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a slice of the string from the beginning to byte
|
||||
/// `end`.
|
||||
///
|
||||
/// Equivalent to `self[0 .. end]`.
|
||||
///
|
||||
/// Panics when `end` does not point to a valid character, or is
|
||||
/// out of bounds.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ops::Index<ops::RangeTo<uint>> for str {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn index(&self, index: &ops::RangeTo<uint>) -> &str {
|
||||
self.slice_to(index.end)
|
||||
// is_char_boundary checks that the index is in [0, .len()]
|
||||
if self.is_char_boundary(index.end) {
|
||||
unsafe { self.slice_unchecked(0, index.end) }
|
||||
} else {
|
||||
super::slice_error_fail(self, 0, index.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a slice of the string from `begin` to its end.
|
||||
///
|
||||
/// Equivalent to `self[begin .. self.len()]`.
|
||||
///
|
||||
/// Panics when `begin` does not point to a valid character, or is
|
||||
/// out of bounds.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ops::Index<ops::RangeFrom<uint>> for str {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn index(&self, index: &ops::RangeFrom<uint>) -> &str {
|
||||
self.slice_from(index.start)
|
||||
// is_char_boundary checks that the index is in [0, .len()]
|
||||
if self.is_char_boundary(index.start) {
|
||||
unsafe { self.slice_unchecked(index.start, self.len()) }
|
||||
} else {
|
||||
super::slice_error_fail(self, index.start, self.len())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ops::Index<ops::FullRange> for str {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
@ -1154,7 +1243,7 @@ mod traits {
|
||||
/// Any string that can be represented as a slice
|
||||
#[unstable(feature = "core",
|
||||
reason = "Instead of taking this bound generically, this trait will be \
|
||||
replaced with one of slicing syntax, deref coercions, or \
|
||||
replaced with one of slicing syntax (&foo[]), deref coercions, or \
|
||||
a more generic conversion trait")]
|
||||
pub trait Str {
|
||||
/// Work with `self` as a slice.
|
||||
@ -1216,9 +1305,6 @@ pub trait StrExt {
|
||||
fn lines<'a>(&'a self) -> Lines<'a>;
|
||||
fn lines_any<'a>(&'a self) -> LinesAny<'a>;
|
||||
fn char_len(&self) -> uint;
|
||||
fn slice<'a>(&'a self, begin: uint, end: uint) -> &'a str;
|
||||
fn slice_from<'a>(&'a self, begin: uint) -> &'a str;
|
||||
fn slice_to<'a>(&'a self, end: uint) -> &'a str;
|
||||
fn slice_chars<'a>(&'a self, begin: uint, end: uint) -> &'a str;
|
||||
unsafe fn slice_unchecked<'a>(&'a self, begin: uint, end: uint) -> &'a str;
|
||||
fn starts_with(&self, pat: &str) -> bool;
|
||||
@ -1340,7 +1426,7 @@ impl StrExt for str {
|
||||
fn lines_any(&self) -> LinesAny {
|
||||
fn f(line: &str) -> &str {
|
||||
let l = line.len();
|
||||
if l > 0 && line.as_bytes()[l - 1] == b'\r' { line.slice(0, l - 1) }
|
||||
if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] }
|
||||
else { line }
|
||||
}
|
||||
|
||||
@ -1351,38 +1437,6 @@ impl StrExt for str {
|
||||
#[inline]
|
||||
fn char_len(&self) -> uint { self.chars().count() }
|
||||
|
||||
#[inline]
|
||||
fn slice(&self, begin: uint, end: uint) -> &str {
|
||||
// is_char_boundary checks that the index is in [0, .len()]
|
||||
if begin <= end &&
|
||||
self.is_char_boundary(begin) &&
|
||||
self.is_char_boundary(end) {
|
||||
unsafe { self.slice_unchecked(begin, end) }
|
||||
} else {
|
||||
slice_error_fail(self, begin, end)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_from(&self, begin: uint) -> &str {
|
||||
// is_char_boundary checks that the index is in [0, .len()]
|
||||
if self.is_char_boundary(begin) {
|
||||
unsafe { self.slice_unchecked(begin, self.len()) }
|
||||
} else {
|
||||
slice_error_fail(self, begin, self.len())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_to(&self, end: uint) -> &str {
|
||||
// is_char_boundary checks that the index is in [0, .len()]
|
||||
if self.is_char_boundary(end) {
|
||||
unsafe { self.slice_unchecked(0, end) }
|
||||
} else {
|
||||
slice_error_fail(self, 0, end)
|
||||
}
|
||||
}
|
||||
|
||||
fn slice_chars(&self, begin: uint, end: uint) -> &str {
|
||||
assert!(begin <= end);
|
||||
let mut count = 0;
|
||||
@ -1423,7 +1477,7 @@ impl StrExt for str {
|
||||
#[inline]
|
||||
fn ends_with(&self, needle: &str) -> bool {
|
||||
let (m, n) = (self.len(), needle.len());
|
||||
m >= n && needle.as_bytes() == &self.as_bytes()[(m-n)..]
|
||||
m >= n && needle.as_bytes() == &self.as_bytes()[m-n..]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -8,6 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(deprecated)]
|
||||
|
||||
use core::finally::{try_finally, Finally};
|
||||
use std::thread::Thread;
|
||||
|
||||
|
@ -14,5 +14,5 @@ mod num;
|
||||
fn test_format_flags() {
|
||||
// No residual flags left by pointer formatting
|
||||
let p = "".as_ptr();
|
||||
assert_eq!(format!("{:p} {:x}", p, 16u), format!("{:p} 10", p));
|
||||
assert_eq!(format!("{:p} {:x}", p, 16), format!("{:p} 10", p));
|
||||
}
|
||||
|
@ -16,115 +16,115 @@ fn test_format_int() {
|
||||
// Formatting integers should select the right implementation based off
|
||||
// the type of the argument. Also, hex/octal/binary should be defined
|
||||
// for integers, but they shouldn't emit the negative sign.
|
||||
assert!(format!("{}", 1i) == "1");
|
||||
assert!(format!("{}", 1is) == "1");
|
||||
assert!(format!("{}", 1i8) == "1");
|
||||
assert!(format!("{}", 1i16) == "1");
|
||||
assert!(format!("{}", 1i32) == "1");
|
||||
assert!(format!("{}", 1i64) == "1");
|
||||
assert!(format!("{}", -1i) == "-1");
|
||||
assert!(format!("{}", -1is) == "-1");
|
||||
assert!(format!("{}", -1i8) == "-1");
|
||||
assert!(format!("{}", -1i16) == "-1");
|
||||
assert!(format!("{}", -1i32) == "-1");
|
||||
assert!(format!("{}", -1i64) == "-1");
|
||||
assert!(format!("{:?}", 1i) == "1i");
|
||||
assert!(format!("{:?}", 1i8) == "1i8");
|
||||
assert!(format!("{:?}", 1i16) == "1i16");
|
||||
assert!(format!("{:?}", 1i32) == "1i32");
|
||||
assert!(format!("{:?}", 1i64) == "1i64");
|
||||
assert!(format!("{:b}", 1i) == "1");
|
||||
assert!(format!("{:?}", 1is) == "1");
|
||||
assert!(format!("{:?}", 1i8) == "1");
|
||||
assert!(format!("{:?}", 1i16) == "1");
|
||||
assert!(format!("{:?}", 1i32) == "1");
|
||||
assert!(format!("{:?}", 1i64) == "1");
|
||||
assert!(format!("{:b}", 1is) == "1");
|
||||
assert!(format!("{:b}", 1i8) == "1");
|
||||
assert!(format!("{:b}", 1i16) == "1");
|
||||
assert!(format!("{:b}", 1i32) == "1");
|
||||
assert!(format!("{:b}", 1i64) == "1");
|
||||
assert!(format!("{:x}", 1i) == "1");
|
||||
assert!(format!("{:x}", 1is) == "1");
|
||||
assert!(format!("{:x}", 1i8) == "1");
|
||||
assert!(format!("{:x}", 1i16) == "1");
|
||||
assert!(format!("{:x}", 1i32) == "1");
|
||||
assert!(format!("{:x}", 1i64) == "1");
|
||||
assert!(format!("{:X}", 1i) == "1");
|
||||
assert!(format!("{:X}", 1is) == "1");
|
||||
assert!(format!("{:X}", 1i8) == "1");
|
||||
assert!(format!("{:X}", 1i16) == "1");
|
||||
assert!(format!("{:X}", 1i32) == "1");
|
||||
assert!(format!("{:X}", 1i64) == "1");
|
||||
assert!(format!("{:o}", 1i) == "1");
|
||||
assert!(format!("{:o}", 1is) == "1");
|
||||
assert!(format!("{:o}", 1i8) == "1");
|
||||
assert!(format!("{:o}", 1i16) == "1");
|
||||
assert!(format!("{:o}", 1i32) == "1");
|
||||
assert!(format!("{:o}", 1i64) == "1");
|
||||
|
||||
assert!(format!("{}", 1u) == "1");
|
||||
assert!(format!("{}", 1us) == "1");
|
||||
assert!(format!("{}", 1u8) == "1");
|
||||
assert!(format!("{}", 1u16) == "1");
|
||||
assert!(format!("{}", 1u32) == "1");
|
||||
assert!(format!("{}", 1u64) == "1");
|
||||
assert!(format!("{:?}", 1u) == "1u");
|
||||
assert!(format!("{:?}", 1u8) == "1u8");
|
||||
assert!(format!("{:?}", 1u16) == "1u16");
|
||||
assert!(format!("{:?}", 1u32) == "1u32");
|
||||
assert!(format!("{:?}", 1u64) == "1u64");
|
||||
assert!(format!("{:b}", 1u) == "1");
|
||||
assert!(format!("{:?}", 1us) == "1");
|
||||
assert!(format!("{:?}", 1u8) == "1");
|
||||
assert!(format!("{:?}", 1u16) == "1");
|
||||
assert!(format!("{:?}", 1u32) == "1");
|
||||
assert!(format!("{:?}", 1u64) == "1");
|
||||
assert!(format!("{:b}", 1us) == "1");
|
||||
assert!(format!("{:b}", 1u8) == "1");
|
||||
assert!(format!("{:b}", 1u16) == "1");
|
||||
assert!(format!("{:b}", 1u32) == "1");
|
||||
assert!(format!("{:b}", 1u64) == "1");
|
||||
assert!(format!("{:x}", 1u) == "1");
|
||||
assert!(format!("{:x}", 1us) == "1");
|
||||
assert!(format!("{:x}", 1u8) == "1");
|
||||
assert!(format!("{:x}", 1u16) == "1");
|
||||
assert!(format!("{:x}", 1u32) == "1");
|
||||
assert!(format!("{:x}", 1u64) == "1");
|
||||
assert!(format!("{:X}", 1u) == "1");
|
||||
assert!(format!("{:X}", 1us) == "1");
|
||||
assert!(format!("{:X}", 1u8) == "1");
|
||||
assert!(format!("{:X}", 1u16) == "1");
|
||||
assert!(format!("{:X}", 1u32) == "1");
|
||||
assert!(format!("{:X}", 1u64) == "1");
|
||||
assert!(format!("{:o}", 1u) == "1");
|
||||
assert!(format!("{:o}", 1us) == "1");
|
||||
assert!(format!("{:o}", 1u8) == "1");
|
||||
assert!(format!("{:o}", 1u16) == "1");
|
||||
assert!(format!("{:o}", 1u32) == "1");
|
||||
assert!(format!("{:o}", 1u64) == "1");
|
||||
|
||||
// Test a larger number
|
||||
assert!(format!("{:b}", 55i) == "110111");
|
||||
assert!(format!("{:o}", 55i) == "67");
|
||||
assert!(format!("{}", 55i) == "55");
|
||||
assert!(format!("{:x}", 55i) == "37");
|
||||
assert!(format!("{:X}", 55i) == "37");
|
||||
assert!(format!("{:b}", 55) == "110111");
|
||||
assert!(format!("{:o}", 55) == "67");
|
||||
assert!(format!("{}", 55) == "55");
|
||||
assert!(format!("{:x}", 55) == "37");
|
||||
assert!(format!("{:X}", 55) == "37");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_int_zero() {
|
||||
assert!(format!("{}", 0i) == "0");
|
||||
assert!(format!("{:?}", 0i) == "0i");
|
||||
assert!(format!("{:b}", 0i) == "0");
|
||||
assert!(format!("{:o}", 0i) == "0");
|
||||
assert!(format!("{:x}", 0i) == "0");
|
||||
assert!(format!("{:X}", 0i) == "0");
|
||||
assert!(format!("{}", 0) == "0");
|
||||
assert!(format!("{:?}", 0) == "0");
|
||||
assert!(format!("{:b}", 0) == "0");
|
||||
assert!(format!("{:o}", 0) == "0");
|
||||
assert!(format!("{:x}", 0) == "0");
|
||||
assert!(format!("{:X}", 0) == "0");
|
||||
|
||||
assert!(format!("{}", 0u) == "0");
|
||||
assert!(format!("{:?}", 0u) == "0u");
|
||||
assert!(format!("{:b}", 0u) == "0");
|
||||
assert!(format!("{:o}", 0u) == "0");
|
||||
assert!(format!("{:x}", 0u) == "0");
|
||||
assert!(format!("{:X}", 0u) == "0");
|
||||
assert!(format!("{}", 0u32) == "0");
|
||||
assert!(format!("{:?}", 0u32) == "0");
|
||||
assert!(format!("{:b}", 0u32) == "0");
|
||||
assert!(format!("{:o}", 0u32) == "0");
|
||||
assert!(format!("{:x}", 0u32) == "0");
|
||||
assert!(format!("{:X}", 0u32) == "0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_int_flags() {
|
||||
assert!(format!("{:3}", 1i) == " 1");
|
||||
assert!(format!("{:>3}", 1i) == " 1");
|
||||
assert!(format!("{:>+3}", 1i) == " +1");
|
||||
assert!(format!("{:<3}", 1i) == "1 ");
|
||||
assert!(format!("{:#}", 1i) == "1");
|
||||
assert!(format!("{:#x}", 10i) == "0xa");
|
||||
assert!(format!("{:#X}", 10i) == "0xA");
|
||||
assert!(format!("{:#5x}", 10i) == " 0xa");
|
||||
assert!(format!("{:#o}", 10i) == "0o12");
|
||||
assert!(format!("{:08x}", 10i) == "0000000a");
|
||||
assert!(format!("{:8x}", 10i) == " a");
|
||||
assert!(format!("{:<8x}", 10i) == "a ");
|
||||
assert!(format!("{:>8x}", 10i) == " a");
|
||||
assert!(format!("{:#08x}", 10i) == "0x00000a");
|
||||
assert!(format!("{:08}", -10i) == "-0000010");
|
||||
assert!(format!("{:3}", 1) == " 1");
|
||||
assert!(format!("{:>3}", 1) == " 1");
|
||||
assert!(format!("{:>+3}", 1) == " +1");
|
||||
assert!(format!("{:<3}", 1) == "1 ");
|
||||
assert!(format!("{:#}", 1) == "1");
|
||||
assert!(format!("{:#x}", 10) == "0xa");
|
||||
assert!(format!("{:#X}", 10) == "0xA");
|
||||
assert!(format!("{:#5x}", 10) == " 0xa");
|
||||
assert!(format!("{:#o}", 10) == "0o12");
|
||||
assert!(format!("{:08x}", 10) == "0000000a");
|
||||
assert!(format!("{:8x}", 10) == " a");
|
||||
assert!(format!("{:<8x}", 10) == "a ");
|
||||
assert!(format!("{:>8x}", 10) == " a");
|
||||
assert!(format!("{:#08x}", 10) == "0x00000a");
|
||||
assert!(format!("{:08}", -10) == "-0000010");
|
||||
assert!(format!("{:x}", -1u8) == "ff");
|
||||
assert!(format!("{:X}", -1u8) == "FF");
|
||||
assert!(format!("{:b}", -1u8) == "11111111");
|
||||
@ -137,12 +137,12 @@ fn test_format_int_flags() {
|
||||
|
||||
#[test]
|
||||
fn test_format_int_sign_padding() {
|
||||
assert!(format!("{:+5}", 1i) == " +1");
|
||||
assert!(format!("{:+5}", -1i) == " -1");
|
||||
assert!(format!("{:05}", 1i) == "00001");
|
||||
assert!(format!("{:05}", -1i) == "-0001");
|
||||
assert!(format!("{:+05}", 1i) == "+0001");
|
||||
assert!(format!("{:+05}", -1i) == "-0001");
|
||||
assert!(format!("{:+5}", 1) == " +1");
|
||||
assert!(format!("{:+5}", -1) == " -1");
|
||||
assert!(format!("{:05}", 1) == "00001");
|
||||
assert!(format!("{:05}", -1) == "-0001");
|
||||
assert!(format!("{:+05}", 1) == "+0001");
|
||||
assert!(format!("{:+05}", -1) == "-0001");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -156,96 +156,98 @@ fn test_format_int_twos_complement() {
|
||||
|
||||
#[test]
|
||||
fn test_format_radix() {
|
||||
assert!(format!("{:04}", radix(3i, 2)) == "0011");
|
||||
assert!(format!("{}", radix(55i, 36)) == "1j");
|
||||
assert!(format!("{:04}", radix(3, 2)) == "0011");
|
||||
assert!(format!("{}", radix(55, 36)) == "1j");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_radix_base_too_large() {
|
||||
let _ = radix(55i, 37);
|
||||
let _ = radix(55, 37);
|
||||
}
|
||||
|
||||
mod uint {
|
||||
mod u32 {
|
||||
use test::Bencher;
|
||||
use core::fmt::radix;
|
||||
use std::rand::{weak_rng, Rng};
|
||||
use std::io::util::NullWriter;
|
||||
|
||||
#[bench]
|
||||
fn format_bin(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{:b}", rng.gen::<uint>()); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{:b}", rng.gen::<u32>()) })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn format_oct(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{:o}", rng.gen::<uint>()); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{:o}", rng.gen::<u32>()) })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn format_dec(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{}", rng.gen::<uint>()); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{}", rng.gen::<u32>()) })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn format_hex(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{:x}", rng.gen::<uint>()); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{:x}", rng.gen::<u32>()) })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn format_show(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{:?}", rng.gen::<uint>()); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{:?}", rng.gen::<u32>()) })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn format_base_36(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{}", radix(rng.gen::<uint>(), 36)); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{}", radix(rng.gen::<u32>(), 36)) })
|
||||
}
|
||||
}
|
||||
|
||||
mod int {
|
||||
mod i32 {
|
||||
use test::Bencher;
|
||||
use core::fmt::radix;
|
||||
use std::rand::{weak_rng, Rng};
|
||||
use std::io::util::NullWriter;
|
||||
|
||||
#[bench]
|
||||
fn format_bin(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{:b}", rng.gen::<int>()); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{:b}", rng.gen::<i32>()) })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn format_oct(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{:o}", rng.gen::<int>()); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{:o}", rng.gen::<i32>()) })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn format_dec(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{}", rng.gen::<int>()); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{}", rng.gen::<i32>()) })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn format_hex(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{:x}", rng.gen::<int>()); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{:x}", rng.gen::<i32>()) })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn format_show(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{:?}", rng.gen::<int>()); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{:?}", rng.gen::<i32>()) })
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn format_base_36(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| { format!("{}", radix(rng.gen::<int>(), 36)); })
|
||||
b.iter(|| { write!(&mut NullWriter, "{}", radix(rng.gen::<i32>(), 36)) })
|
||||
}
|
||||
}
|
||||
|
@ -120,18 +120,32 @@ fn test_iterator_enumerate() {
|
||||
fn test_iterator_peekable() {
|
||||
let xs = vec![0u, 1, 2, 3, 4, 5];
|
||||
let mut it = xs.iter().map(|&x|x).peekable();
|
||||
|
||||
assert_eq!(it.len(), 6);
|
||||
assert_eq!(it.peek().unwrap(), &0);
|
||||
assert_eq!(it.len(), 6);
|
||||
assert_eq!(it.next().unwrap(), 0);
|
||||
assert_eq!(it.len(), 5);
|
||||
assert_eq!(it.next().unwrap(), 1);
|
||||
assert_eq!(it.len(), 4);
|
||||
assert_eq!(it.next().unwrap(), 2);
|
||||
assert_eq!(it.len(), 3);
|
||||
assert_eq!(it.peek().unwrap(), &3);
|
||||
assert_eq!(it.len(), 3);
|
||||
assert_eq!(it.peek().unwrap(), &3);
|
||||
assert_eq!(it.len(), 3);
|
||||
assert_eq!(it.next().unwrap(), 3);
|
||||
assert_eq!(it.len(), 2);
|
||||
assert_eq!(it.next().unwrap(), 4);
|
||||
assert_eq!(it.len(), 1);
|
||||
assert_eq!(it.peek().unwrap(), &5);
|
||||
assert_eq!(it.len(), 1);
|
||||
assert_eq!(it.next().unwrap(), 5);
|
||||
assert_eq!(it.len(), 0);
|
||||
assert!(it.peek().is_none());
|
||||
assert_eq!(it.len(), 0);
|
||||
assert!(it.next().is_none());
|
||||
assert_eq!(it.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -166,24 +180,45 @@ fn test_iterator_skip() {
|
||||
let ys = [13, 15, 16, 17, 19, 20, 30];
|
||||
let mut it = xs.iter().skip(5);
|
||||
let mut i = 0;
|
||||
for &x in it {
|
||||
while let Some(&x) = it.next() {
|
||||
assert_eq!(x, ys[i]);
|
||||
i += 1;
|
||||
assert_eq!(it.len(), xs.len()-5-i);
|
||||
}
|
||||
assert_eq!(i, ys.len());
|
||||
assert_eq!(it.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_take() {
|
||||
let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19];
|
||||
let ys = [0u, 1, 2, 3, 5];
|
||||
let xs = [0us, 1, 2, 3, 5, 13, 15, 16, 17, 19];
|
||||
let ys = [0us, 1, 2, 3, 5];
|
||||
let mut it = xs.iter().take(5);
|
||||
let mut i = 0;
|
||||
for &x in it {
|
||||
assert_eq!(it.len(), 5);
|
||||
while let Some(&x) = it.next() {
|
||||
assert_eq!(x, ys[i]);
|
||||
i += 1;
|
||||
assert_eq!(it.len(), 5-i);
|
||||
}
|
||||
assert_eq!(i, ys.len());
|
||||
assert_eq!(it.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_take_short() {
|
||||
let xs = [0us, 1, 2, 3];
|
||||
let ys = [0us, 1, 2, 3];
|
||||
let mut it = xs.iter().take(5);
|
||||
let mut i = 0;
|
||||
assert_eq!(it.len(), 4);
|
||||
while let Some(&x) = it.next() {
|
||||
assert_eq!(x, ys[i]);
|
||||
i += 1;
|
||||
assert_eq!(it.len(), 4-i);
|
||||
}
|
||||
assert_eq!(i, ys.len());
|
||||
assert_eq!(it.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -585,7 +620,7 @@ fn check_randacc_iter<A, T>(a: T, len: uint) where
|
||||
fn test_double_ended_flat_map() {
|
||||
let u = [0u,1];
|
||||
let v = [5u,6,7,8];
|
||||
let mut it = u.iter().flat_map(|x| v[(*x)..v.len()].iter());
|
||||
let mut it = u.iter().flat_map(|x| v[*x..v.len()].iter());
|
||||
assert_eq!(it.next_back().unwrap(), &8);
|
||||
assert_eq!(it.next().unwrap(), &5);
|
||||
assert_eq!(it.next_back().unwrap(), &7);
|
||||
@ -828,6 +863,24 @@ fn test_repeat() {
|
||||
assert_eq!(it.next(), Some(42u));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fuse() {
|
||||
let mut it = 0us..3;
|
||||
assert_eq!(it.len(), 3);
|
||||
assert_eq!(it.next(), Some(0us));
|
||||
assert_eq!(it.len(), 2);
|
||||
assert_eq!(it.next(), Some(1us));
|
||||
assert_eq!(it.len(), 1);
|
||||
assert_eq!(it.next(), Some(2us));
|
||||
assert_eq!(it.len(), 0);
|
||||
assert_eq!(it.next(), None);
|
||||
assert_eq!(it.len(), 0);
|
||||
assert_eq!(it.next(), None);
|
||||
assert_eq!(it.len(), 0);
|
||||
assert_eq!(it.next(), None);
|
||||
assert_eq!(it.len(), 0);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_rposition(b: &mut Bencher) {
|
||||
let it: Vec<uint> = range(0u, 300).collect();
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use core::cmp::PartialEq;
|
||||
use core::fmt::Show;
|
||||
use core::fmt::Debug;
|
||||
use core::num::{NumCast, cast};
|
||||
use core::ops::{Add, Sub, Mul, Div, Rem};
|
||||
use core::marker::Copy;
|
||||
@ -37,7 +37,7 @@ pub fn test_num<T>(ten: T, two: T) where
|
||||
T: PartialEq + NumCast
|
||||
+ Add<Output=T> + Sub<Output=T>
|
||||
+ Mul<Output=T> + Div<Output=T>
|
||||
+ Rem<Output=T> + Show
|
||||
+ Rem<Output=T> + Debug
|
||||
+ Copy
|
||||
{
|
||||
assert_eq!(ten.add(two), cast(12i).unwrap());
|
||||
|
@ -14,11 +14,11 @@ pub fn op2() -> Result<int, &'static str> { Err("sadface") }
|
||||
#[test]
|
||||
pub fn test_and() {
|
||||
assert_eq!(op1().and(Ok(667i)).unwrap(), 667);
|
||||
assert_eq!(op1().and(Err::<(), &'static str>("bad")).unwrap_err(),
|
||||
assert_eq!(op1().and(Err::<i32, &'static str>("bad")).unwrap_err(),
|
||||
"bad");
|
||||
|
||||
assert_eq!(op2().and(Ok(667i)).unwrap_err(), "sadface");
|
||||
assert_eq!(op2().and(Err::<(),&'static str>("bad")).unwrap_err(),
|
||||
assert_eq!(op2().and(Err::<i32,&'static str>("bad")).unwrap_err(),
|
||||
"sadface");
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@ pub fn test_fmt_default() {
|
||||
let err: Result<int, &'static str> = Err("Err");
|
||||
|
||||
let s = format!("{:?}", ok);
|
||||
assert_eq!(s, "Ok(100i)");
|
||||
assert_eq!(s, "Ok(100)");
|
||||
let s = format!("{:?}", err);
|
||||
assert_eq!(s, "Err(\"Err\")");
|
||||
}
|
||||
|
@ -60,9 +60,9 @@ fn test_tuple_cmp() {
|
||||
#[test]
|
||||
fn test_show() {
|
||||
let s = format!("{:?}", (1i,));
|
||||
assert_eq!(s, "(1i,)");
|
||||
assert_eq!(s, "(1,)");
|
||||
let s = format!("{:?}", (1i, true));
|
||||
assert_eq!(s, "(1i, true)");
|
||||
assert_eq!(s, "(1, true)");
|
||||
let s = format!("{:?}", (1i, "hi", true));
|
||||
assert_eq!(s, "(1i, \"hi\", true)");
|
||||
assert_eq!(s, "(1, \"hi\", true)");
|
||||
}
|
||||
|
@ -550,7 +550,7 @@ impl Fail {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::String for Fail {
|
||||
impl fmt::Display for Fail {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
ArgumentMissing(ref nm) => {
|
||||
@ -899,7 +899,7 @@ fn each_split_within<F>(ss: &str, lim: uint, mut it: F) -> bool where
|
||||
(B, Cr, UnderLim) => { B }
|
||||
(B, Cr, OverLim) if (i - last_start + 1) > lim
|
||||
=> panic!("word starting with {} longer than limit!",
|
||||
&ss[last_start..(i + 1)]),
|
||||
&ss[last_start..i + 1]),
|
||||
(B, Cr, OverLim) => {
|
||||
*cont = it(&ss[slice_start..last_end]);
|
||||
slice_start = last_start;
|
||||
|
@ -362,19 +362,19 @@ impl<'a> Id<'a> {
|
||||
///
|
||||
/// Passing an invalid string (containing spaces, brackets,
|
||||
/// quotes, ...) will return an empty `Err` value.
|
||||
pub fn new<Name: IntoCow<'a, String, str>>(name: Name) -> Result<Id<'a>, ()> {
|
||||
pub fn new<Name: IntoCow<'a, String, str>>(name: Name) -> Option<Id<'a>> {
|
||||
let name = name.into_cow();
|
||||
{
|
||||
let mut chars = name.chars();
|
||||
match chars.next() {
|
||||
Some(c) if is_letter_or_underscore(c) => { ; },
|
||||
_ => return Err(())
|
||||
_ => return None
|
||||
}
|
||||
if !chars.all(is_constituent) {
|
||||
return Err(());
|
||||
return None
|
||||
}
|
||||
}
|
||||
return Ok(Id{ name: name });
|
||||
return Some(Id{ name: name });
|
||||
|
||||
fn is_letter_or_underscore(c: char) -> bool {
|
||||
in_range('a', c, 'z') || in_range('A', c, 'Z') || c == '_'
|
||||
@ -878,8 +878,8 @@ r#"digraph syntax_tree {
|
||||
fn simple_id_construction() {
|
||||
let id1 = Id::new("hello");
|
||||
match id1 {
|
||||
Ok(_) => {;},
|
||||
Err(_) => panic!("'hello' is not a valid value for id anymore")
|
||||
Some(_) => {;},
|
||||
None => panic!("'hello' is not a valid value for id anymore")
|
||||
}
|
||||
}
|
||||
|
||||
@ -887,8 +887,8 @@ r#"digraph syntax_tree {
|
||||
fn badly_formatted_id() {
|
||||
let id2 = Id::new("Weird { struct : ure } !!!");
|
||||
match id2 {
|
||||
Ok(_) => panic!("graphviz id suddenly allows spaces, brackets and stuff"),
|
||||
Err(_) => {;}
|
||||
Some(_) => panic!("graphviz id suddenly allows spaces, brackets and stuff"),
|
||||
None => {;}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ impl<'a,T> FromIterator<T> for MaybeOwnedVector<'a,T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,T:fmt::Show> fmt::Show for MaybeOwnedVector<'a,T> {
|
||||
impl<'a,T:fmt::Debug> fmt::Debug for MaybeOwnedVector<'a,T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.as_slice().fmt(f)
|
||||
}
|
||||
|
@ -557,7 +557,8 @@ pub mod types {
|
||||
pub type mode_t = u16;
|
||||
pub type ssize_t = i32;
|
||||
}
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[cfg(any(target_arch = "x86",
|
||||
target_arch = "powerpc"))]
|
||||
pub mod posix01 {
|
||||
use types::os::arch::c95::{c_short, c_long, time_t};
|
||||
use types::os::arch::posix88::{dev_t, gid_t, ino_t};
|
||||
@ -648,8 +649,7 @@ pub mod types {
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_arch = "mips",
|
||||
target_arch = "mipsel",
|
||||
target_arch = "powerpc"))]
|
||||
target_arch = "mipsel"))]
|
||||
pub mod posix01 {
|
||||
use types::os::arch::c95::{c_long, c_ulong, time_t};
|
||||
use types::os::arch::posix88::{gid_t, ino_t};
|
||||
@ -2493,7 +2493,8 @@ pub mod consts {
|
||||
#[cfg(any(target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64"))]
|
||||
target_arch = "aarch64",
|
||||
target_arch = "powerpc"))]
|
||||
pub mod posix88 {
|
||||
use types::os::arch::c95::c_int;
|
||||
use types::common::c95::c_void;
|
||||
@ -2706,8 +2707,7 @@ pub mod consts {
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "mips",
|
||||
target_arch = "mipsel",
|
||||
target_arch = "powerpc"))]
|
||||
target_arch = "mipsel"))]
|
||||
pub mod posix88 {
|
||||
use types::os::arch::c95::c_int;
|
||||
use types::common::c95::c_void;
|
||||
@ -3004,7 +3004,8 @@ pub mod consts {
|
||||
#[cfg(any(target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "x86",
|
||||
target_arch = "x86_64"))]
|
||||
target_arch = "x86_64",
|
||||
target_arch = "powerpc"))]
|
||||
pub mod bsd44 {
|
||||
use types::os::arch::c95::c_int;
|
||||
|
||||
@ -3052,8 +3053,7 @@ pub mod consts {
|
||||
pub const SHUT_RDWR: c_int = 2;
|
||||
}
|
||||
#[cfg(any(target_arch = "mips",
|
||||
target_arch = "mipsel",
|
||||
target_arch = "powerpc"))]
|
||||
target_arch = "mipsel"))]
|
||||
pub mod bsd44 {
|
||||
use types::os::arch::c95::c_int;
|
||||
|
||||
@ -3101,7 +3101,8 @@ pub mod consts {
|
||||
#[cfg(any(target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64"))]
|
||||
target_arch = "aarch64",
|
||||
target_arch = "powerpc"))]
|
||||
pub mod extra {
|
||||
use types::os::arch::c95::c_int;
|
||||
|
||||
@ -3129,8 +3130,7 @@ pub mod consts {
|
||||
pub const MAP_STACK : c_int = 0x020000;
|
||||
}
|
||||
#[cfg(any(target_arch = "mips",
|
||||
target_arch = "mipsel",
|
||||
target_arch = "powerpc"))]
|
||||
target_arch = "mipsel"))]
|
||||
pub mod extra {
|
||||
use types::os::arch::c95::c_int;
|
||||
|
||||
@ -4650,13 +4650,13 @@ pub mod funcs {
|
||||
use types::os::arch::c95::c_int;
|
||||
use types::os::common::posix01::sighandler_t;
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[cfg(not(all(target_os = "android", target_arch = "arm")))]
|
||||
extern {
|
||||
pub fn signal(signum: c_int,
|
||||
handler: sighandler_t) -> sighandler_t;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[cfg(all(target_os = "android", target_arch = "arm"))]
|
||||
extern {
|
||||
#[link_name = "bsd_signal"]
|
||||
pub fn signal(signum: c_int,
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use regex::Regex;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::cmp;
|
||||
|
||||
@ -34,7 +33,7 @@ fn parse_log_level(level: &str) -> Option<u32> {
|
||||
///
|
||||
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
|
||||
/// std::). Also supports string log levels of error, warn, info, and debug
|
||||
pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<Regex>) {
|
||||
pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<String>) {
|
||||
let mut dirs = Vec::new();
|
||||
|
||||
let mut parts = spec.split('/');
|
||||
@ -80,17 +79,7 @@ pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<Regex>) {
|
||||
});
|
||||
}});
|
||||
|
||||
let filter = filter.map_or(None, |filter| {
|
||||
match Regex::new(filter) {
|
||||
Ok(re) => Some(re),
|
||||
Err(e) => {
|
||||
println!("warning: invalid regex filter - {:?}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (dirs, filter);
|
||||
(dirs, filter.map(|s| s.to_string()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -123,11 +123,11 @@
|
||||
//!
|
||||
//! # Filtering results
|
||||
//!
|
||||
//! A RUST_LOG directive may include a regex filter. The syntax is to append `/`
|
||||
//! followed by a regex. Each message is checked against the regex, and is only
|
||||
//! logged if it matches. Note that the matching is done after formatting the log
|
||||
//! string but before adding any logging meta-data. There is a single filter for all
|
||||
//! modules.
|
||||
//! A RUST_LOG directive may include a string filter. The syntax is to append
|
||||
//! `/` followed by a string. Each message is checked against the string and is
|
||||
//! only logged if it contains the string. Note that the matching is done after
|
||||
//! formatting the log string but before adding any logging meta-data. There is
|
||||
//! a single filter for all modules.
|
||||
//!
|
||||
//! Some examples:
|
||||
//!
|
||||
@ -179,20 +179,17 @@
|
||||
#![feature(rustc_private)]
|
||||
#![feature(std_misc)]
|
||||
|
||||
extern crate regex;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::io::LineBufferedWriter;
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::os;
|
||||
use std::ptr;
|
||||
use std::rt;
|
||||
use std::slice;
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
use directive::LOG_LEVEL_NAMES;
|
||||
|
||||
#[macro_use]
|
||||
@ -215,8 +212,8 @@ static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL;
|
||||
static mut DIRECTIVES: *const Vec<directive::LogDirective> =
|
||||
0 as *const Vec<directive::LogDirective>;
|
||||
|
||||
/// Optional regex filter.
|
||||
static mut FILTER: *const Regex = 0 as *const _;
|
||||
/// Optional filter.
|
||||
static mut FILTER: *const String = 0 as *const _;
|
||||
|
||||
/// Debug log level
|
||||
pub const DEBUG: u32 = 4;
|
||||
@ -246,21 +243,15 @@ struct DefaultLogger {
|
||||
}
|
||||
|
||||
/// Wraps the log level with fmt implementations.
|
||||
#[derive(Copy, PartialEq, PartialOrd)]
|
||||
#[derive(Copy, PartialEq, PartialOrd, Show)]
|
||||
pub struct LogLevel(pub u32);
|
||||
|
||||
impl fmt::Show for LogLevel {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::String for LogLevel {
|
||||
impl fmt::Display for LogLevel {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let LogLevel(level) = *self;
|
||||
match LOG_LEVEL_NAMES.get(level as uint - 1) {
|
||||
Some(ref name) => fmt::String::fmt(name, fmt),
|
||||
None => fmt::String::fmt(&level, fmt)
|
||||
Some(ref name) => fmt::Display::fmt(name, fmt),
|
||||
None => fmt::Display::fmt(&level, fmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -300,7 +291,7 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
|
||||
// Test the literal string from args against the current filter, if there
|
||||
// is one.
|
||||
match unsafe { FILTER.as_ref() } {
|
||||
Some(filter) if !filter.is_match(&args.to_string()[]) => return,
|
||||
Some(filter) if !args.to_string().contains(&filter[]) => return,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@ -444,10 +435,10 @@ fn init() {
|
||||
assert!(!DIRECTIVES.is_null());
|
||||
let _directives: Box<Vec<directive::LogDirective>> =
|
||||
mem::transmute(DIRECTIVES);
|
||||
DIRECTIVES = 0 as *const Vec<directive::LogDirective>;
|
||||
DIRECTIVES = ptr::null();
|
||||
|
||||
if !FILTER.is_null() {
|
||||
let _filter: Box<Regex> = mem::transmute(FILTER);
|
||||
let _filter: Box<String> = mem::transmute(FILTER);
|
||||
FILTER = 0 as *const _;
|
||||
}
|
||||
});
|
||||
|
@ -174,7 +174,7 @@ impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {
|
||||
// reset state
|
||||
self.init(&[0u32; KEY_WORDS]);
|
||||
// set key in place
|
||||
let key = self.state.slice_mut(4, 4+KEY_WORDS);
|
||||
let key = &mut self.state[4 .. 4+KEY_WORDS];
|
||||
for (k, s) in key.iter_mut().zip(seed.iter()) {
|
||||
*k = *s;
|
||||
}
|
||||
@ -292,4 +292,3 @@ mod test {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ impl Writer for SeekableMemWriter {
|
||||
|
||||
// Do the necessary writes
|
||||
if left.len() > 0 {
|
||||
slice::bytes::copy_memory(self.buf.slice_from_mut(self.pos), left);
|
||||
slice::bytes::copy_memory(&mut self.buf[self.pos..], left);
|
||||
}
|
||||
if right.len() > 0 {
|
||||
self.buf.push_all(right);
|
||||
|
@ -42,6 +42,7 @@ pub use self::EbmlEncoderTag::*;
|
||||
pub use self::Error::*;
|
||||
|
||||
use std::str;
|
||||
use std::fmt;
|
||||
|
||||
pub mod io;
|
||||
|
||||
@ -117,6 +118,13 @@ pub enum Error {
|
||||
IoError(std::io::IoError),
|
||||
ApplicationError(String)
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// FIXME: this should be a more useful display form
|
||||
fmt::Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
// --------------------------------------
|
||||
|
||||
pub mod reader {
|
||||
|
@ -1,275 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Enable this to squash warnings due to exporting pieces of the representation
|
||||
// for use with the regex! macro. See lib.rs for explanation.
|
||||
|
||||
pub use self::Inst::*;
|
||||
|
||||
use std::cmp;
|
||||
use std::iter::repeat;
|
||||
use parse;
|
||||
use parse::{
|
||||
Flags, FLAG_EMPTY,
|
||||
Nothing, Literal, Dot, AstClass, Begin, End, WordBoundary, Capture, Cat, Alt,
|
||||
Rep,
|
||||
ZeroOne, ZeroMore, OneMore,
|
||||
};
|
||||
|
||||
type InstIdx = uint;
|
||||
|
||||
#[derive(Show, Clone)]
|
||||
pub enum Inst {
|
||||
// When a Match instruction is executed, the current thread is successful.
|
||||
Match,
|
||||
|
||||
// The OneChar instruction matches a literal character.
|
||||
// The flags indicate whether to do a case insensitive match.
|
||||
OneChar(char, Flags),
|
||||
|
||||
// The CharClass instruction tries to match one input character against
|
||||
// the range of characters given.
|
||||
// The flags indicate whether to do a case insensitive match and whether
|
||||
// the character class is negated or not.
|
||||
CharClass(Vec<(char, char)>, Flags),
|
||||
|
||||
// Matches any character except new lines.
|
||||
// The flags indicate whether to include the '\n' character.
|
||||
Any(Flags),
|
||||
|
||||
// Matches the beginning of the string, consumes no characters.
|
||||
// The flags indicate whether it matches if the preceding character
|
||||
// is a new line.
|
||||
EmptyBegin(Flags),
|
||||
|
||||
// Matches the end of the string, consumes no characters.
|
||||
// The flags indicate whether it matches if the proceeding character
|
||||
// is a new line.
|
||||
EmptyEnd(Flags),
|
||||
|
||||
// Matches a word boundary (\w on one side and \W \A or \z on the other),
|
||||
// and consumes no character.
|
||||
// The flags indicate whether this matches a word boundary or something
|
||||
// that isn't a word boundary.
|
||||
EmptyWordBoundary(Flags),
|
||||
|
||||
// Saves the current position in the input string to the Nth save slot.
|
||||
Save(uint),
|
||||
|
||||
// Jumps to the instruction at the index given.
|
||||
Jump(InstIdx),
|
||||
|
||||
// Jumps to the instruction at the first index given. If that leads to
|
||||
// a panic state, then the instruction at the second index given is
|
||||
// tried.
|
||||
Split(InstIdx, InstIdx),
|
||||
}
|
||||
|
||||
/// Program represents a compiled regular expression. Once an expression is
|
||||
/// compiled, its representation is immutable and will never change.
|
||||
///
|
||||
/// All of the data in a compiled expression is wrapped in "MaybeStatic" or
|
||||
/// "MaybeOwned" types so that a `Program` can be represented as static data.
|
||||
/// (This makes it convenient and efficient for use with the `regex!` macro.)
|
||||
#[derive(Clone)]
|
||||
pub struct Program {
|
||||
/// A sequence of instructions.
|
||||
pub insts: Vec<Inst>,
|
||||
/// If the regular expression requires a literal prefix in order to have a
|
||||
/// match, that prefix is stored here. (It's used in the VM to implement
|
||||
/// an optimization.)
|
||||
pub prefix: String,
|
||||
}
|
||||
|
||||
impl Program {
|
||||
/// Compiles a Regex given its AST.
|
||||
pub fn new(ast: parse::Ast) -> (Program, Vec<Option<String>>) {
|
||||
let mut c = Compiler {
|
||||
insts: Vec::with_capacity(100),
|
||||
names: Vec::with_capacity(10),
|
||||
};
|
||||
|
||||
c.insts.push(Save(0));
|
||||
c.compile(ast);
|
||||
c.insts.push(Save(1));
|
||||
c.insts.push(Match);
|
||||
|
||||
// Try to discover a literal string prefix.
|
||||
// This is a bit hacky since we have to skip over the initial
|
||||
// 'Save' instruction.
|
||||
let mut pre = String::with_capacity(5);
|
||||
for inst in c.insts[1..].iter() {
|
||||
match *inst {
|
||||
OneChar(c, FLAG_EMPTY) => pre.push(c),
|
||||
_ => break
|
||||
}
|
||||
}
|
||||
|
||||
let Compiler { insts, names } = c;
|
||||
let prog = Program {
|
||||
insts: insts,
|
||||
prefix: pre,
|
||||
};
|
||||
(prog, names)
|
||||
}
|
||||
|
||||
/// Returns the total number of capture groups in the regular expression.
|
||||
/// This includes the zeroth capture.
|
||||
pub fn num_captures(&self) -> uint {
|
||||
let mut n = 0;
|
||||
for inst in self.insts.iter() {
|
||||
match *inst {
|
||||
Save(c) => n = cmp::max(n, c+1),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// There's exactly 2 Save slots for every capture.
|
||||
n / 2
|
||||
}
|
||||
}
|
||||
|
||||
struct Compiler<'r> {
|
||||
insts: Vec<Inst>,
|
||||
names: Vec<Option<String>>,
|
||||
}
|
||||
|
||||
// The compiler implemented here is extremely simple. Most of the complexity
|
||||
// in this crate is in the parser or the VM.
|
||||
// The only tricky thing here is patching jump/split instructions to point to
|
||||
// the right instruction.
|
||||
impl<'r> Compiler<'r> {
|
||||
fn compile(&mut self, ast: parse::Ast) {
|
||||
match ast {
|
||||
Nothing => {},
|
||||
Literal(c, flags) => self.push(OneChar(c, flags)),
|
||||
Dot(nl) => self.push(Any(nl)),
|
||||
AstClass(ranges, flags) =>
|
||||
self.push(CharClass(ranges, flags)),
|
||||
Begin(flags) => self.push(EmptyBegin(flags)),
|
||||
End(flags) => self.push(EmptyEnd(flags)),
|
||||
WordBoundary(flags) => self.push(EmptyWordBoundary(flags)),
|
||||
Capture(cap, name, x) => {
|
||||
let len = self.names.len();
|
||||
if cap >= len {
|
||||
self.names.extend(repeat(None).take(10 + cap - len))
|
||||
}
|
||||
self.names[cap] = name;
|
||||
|
||||
self.push(Save(2 * cap));
|
||||
self.compile(*x);
|
||||
self.push(Save(2 * cap + 1));
|
||||
}
|
||||
Cat(xs) => {
|
||||
for x in xs.into_iter() {
|
||||
self.compile(x)
|
||||
}
|
||||
}
|
||||
Alt(x, y) => {
|
||||
let split = self.empty_split(); // push: split 0, 0
|
||||
let j1 = self.insts.len();
|
||||
self.compile(*x); // push: insts for x
|
||||
let jmp = self.empty_jump(); // push: jmp 0
|
||||
let j2 = self.insts.len();
|
||||
self.compile(*y); // push: insts for y
|
||||
let j3 = self.insts.len();
|
||||
|
||||
self.set_split(split, j1, j2); // split 0, 0 -> split j1, j2
|
||||
self.set_jump(jmp, j3); // jmp 0 -> jmp j3
|
||||
}
|
||||
Rep(x, ZeroOne, g) => {
|
||||
let split = self.empty_split();
|
||||
let j1 = self.insts.len();
|
||||
self.compile(*x);
|
||||
let j2 = self.insts.len();
|
||||
|
||||
if g.is_greedy() {
|
||||
self.set_split(split, j1, j2);
|
||||
} else {
|
||||
self.set_split(split, j2, j1);
|
||||
}
|
||||
}
|
||||
Rep(x, ZeroMore, g) => {
|
||||
let j1 = self.insts.len();
|
||||
let split = self.empty_split();
|
||||
let j2 = self.insts.len();
|
||||
self.compile(*x);
|
||||
let jmp = self.empty_jump();
|
||||
let j3 = self.insts.len();
|
||||
|
||||
self.set_jump(jmp, j1);
|
||||
if g.is_greedy() {
|
||||
self.set_split(split, j2, j3);
|
||||
} else {
|
||||
self.set_split(split, j3, j2);
|
||||
}
|
||||
}
|
||||
Rep(x, OneMore, g) => {
|
||||
let j1 = self.insts.len();
|
||||
self.compile(*x);
|
||||
let split = self.empty_split();
|
||||
let j2 = self.insts.len();
|
||||
|
||||
if g.is_greedy() {
|
||||
self.set_split(split, j1, j2);
|
||||
} else {
|
||||
self.set_split(split, j2, j1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends the given instruction to the program.
|
||||
#[inline]
|
||||
fn push(&mut self, x: Inst) {
|
||||
self.insts.push(x)
|
||||
}
|
||||
|
||||
/// Appends an *empty* `Split` instruction to the program and returns
|
||||
/// the index of that instruction. (The index can then be used to "patch"
|
||||
/// the actual locations of the split in later.)
|
||||
#[inline]
|
||||
fn empty_split(&mut self) -> InstIdx {
|
||||
self.insts.push(Split(0, 0));
|
||||
self.insts.len() - 1
|
||||
}
|
||||
|
||||
/// Sets the left and right locations of a `Split` instruction at index
|
||||
/// `i` to `pc1` and `pc2`, respectively.
|
||||
/// If the instruction at index `i` isn't a `Split` instruction, then
|
||||
/// `panic!` is called.
|
||||
#[inline]
|
||||
fn set_split(&mut self, i: InstIdx, pc1: InstIdx, pc2: InstIdx) {
|
||||
let split = &mut self.insts[i];
|
||||
match *split {
|
||||
Split(_, _) => *split = Split(pc1, pc2),
|
||||
_ => panic!("BUG: Invalid split index."),
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends an *empty* `Jump` instruction to the program and returns the
|
||||
/// index of that instruction.
|
||||
#[inline]
|
||||
fn empty_jump(&mut self) -> InstIdx {
|
||||
self.insts.push(Jump(0));
|
||||
self.insts.len() - 1
|
||||
}
|
||||
|
||||
/// Sets the location of a `Jump` instruction at index `i` to `pc`.
|
||||
/// If the instruction at index `i` isn't a `Jump` instruction, then
|
||||
/// `panic!` is called.
|
||||
#[inline]
|
||||
fn set_jump(&mut self, i: InstIdx, pc: InstIdx) {
|
||||
let jmp = &mut self.insts[i];
|
||||
match *jmp {
|
||||
Jump(_) => *jmp = Jump(pc),
|
||||
_ => panic!("BUG: Invalid jump index."),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
//
|
||||
// ignore-lexer-test FIXME #15679
|
||||
|
||||
//! Regular expressions implemented in Rust
|
||||
//!
|
||||
//! For official documentation, see the rust-lang/regex crate
|
||||
#![crate_name = "regex"]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![unstable(feature = "rustc_private",
|
||||
reason = "use the crates.io `regex` library instead")]
|
||||
#![feature(staged_api)]
|
||||
#![staged_api]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/nightly/",
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
|
||||
#![allow(unknown_features)]
|
||||
#![feature(slicing_syntax)]
|
||||
#![feature(box_syntax)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![deny(missing_docs)]
|
||||
#![feature(collections)]
|
||||
#![feature(core)]
|
||||
#![feature(unicode)]
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate "test" as stdtest;
|
||||
#[cfg(test)]
|
||||
extern crate rand;
|
||||
|
||||
// During tests, this links with the `regex` crate so that the `regex!` macro
|
||||
// can be tested.
|
||||
#[cfg(test)]
|
||||
extern crate regex;
|
||||
|
||||
// Unicode tables for character classes are defined in libunicode
|
||||
extern crate unicode;
|
||||
|
||||
pub use parse::Error;
|
||||
pub use re::{Regex, Captures, SubCaptures, SubCapturesPos};
|
||||
pub use re::{FindCaptures, FindMatches};
|
||||
pub use re::{Replacer, NoExpand, RegexSplits, RegexSplitsN};
|
||||
pub use re::{quote, is_match};
|
||||
|
||||
mod compile;
|
||||
mod parse;
|
||||
mod re;
|
||||
mod vm;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
/// The `native` module exists to support the `regex!` macro. Do not use.
|
||||
#[doc(hidden)]
|
||||
pub mod native {
|
||||
// Exporting this stuff is bad form, but it's necessary for two reasons.
|
||||
// Firstly, the `regex!` syntax extension is in a different crate and
|
||||
// requires access to the representation of a regex (particularly the
|
||||
// instruction set) in order to compile to native Rust. This could be
|
||||
// mitigated if `regex!` was defined in the same crate, but this has
|
||||
// undesirable consequences (such as requiring a dependency on
|
||||
// `libsyntax`).
|
||||
//
|
||||
// Secondly, the code generated by `regex!` must *also* be able
|
||||
// to access various functions in this crate to reduce code duplication
|
||||
// and to provide a value with precisely the same `Regex` type in this
|
||||
// crate. This, AFAIK, is impossible to mitigate.
|
||||
//
|
||||
// On the bright side, `rustdoc` lets us hide this from the public API
|
||||
// documentation.
|
||||
pub use compile::{
|
||||
Program,
|
||||
OneChar, CharClass, Any, Save, Jump, Split,
|
||||
Match, EmptyBegin, EmptyEnd, EmptyWordBoundary,
|
||||
};
|
||||
pub use parse::{
|
||||
FLAG_EMPTY, FLAG_NOCASE, FLAG_MULTI, FLAG_DOTNL,
|
||||
FLAG_SWAP_GREED, FLAG_NEGATED,
|
||||
};
|
||||
pub use re::{Dynamic, ExDynamic, Native, ExNative};
|
||||
pub use vm::{
|
||||
MatchKind, Exists, Location, Submatches,
|
||||
StepState, StepMatchEarlyReturn, StepMatch, StepContinue,
|
||||
CharReader, find_prefix,
|
||||
};
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,682 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub use self::NamesIter::*;
|
||||
pub use self::Regex::*;
|
||||
|
||||
use std::borrow::IntoCow;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::string::CowString;
|
||||
|
||||
use compile::Program;
|
||||
use parse;
|
||||
use vm;
|
||||
use vm::{CaptureLocs, MatchKind, Exists, Location, Submatches};
|
||||
|
||||
/// Escapes all regular expression meta characters in `text`.
|
||||
///
|
||||
/// The string returned may be safely used as a literal in a regular
|
||||
/// expression.
|
||||
pub fn quote(text: &str) -> String {
|
||||
let mut quoted = String::with_capacity(text.len());
|
||||
for c in text.chars() {
|
||||
if parse::is_punct(c) {
|
||||
quoted.push('\\')
|
||||
}
|
||||
quoted.push(c);
|
||||
}
|
||||
quoted
|
||||
}
|
||||
|
||||
/// Tests if the given regular expression matches somewhere in the text given.
|
||||
///
|
||||
/// If there was a problem compiling the regular expression, an error is
|
||||
/// returned.
|
||||
///
|
||||
/// To find submatches, split or replace text, you'll need to compile an
|
||||
/// expression first.
|
||||
///
|
||||
/// Note that you should prefer the `regex!` macro when possible. For example,
|
||||
/// `regex!("...").is_match("...")`.
|
||||
pub fn is_match(regex: &str, text: &str) -> Result<bool, parse::Error> {
|
||||
Regex::new(regex).map(|r| r.is_match(text))
|
||||
}
|
||||
|
||||
/// A compiled regular expression
|
||||
#[derive(Clone)]
|
||||
pub enum Regex {
|
||||
// The representation of `Regex` is exported to support the `regex!`
|
||||
// syntax extension. Do not rely on it.
|
||||
//
|
||||
// See the comments for the `program` module in `lib.rs` for a more
|
||||
// detailed explanation for what `regex!` requires.
|
||||
#[doc(hidden)]
|
||||
Dynamic(ExDynamic),
|
||||
#[doc(hidden)]
|
||||
Native(ExNative),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[doc(hidden)]
|
||||
pub struct ExDynamic {
|
||||
original: String,
|
||||
names: Vec<Option<String>>,
|
||||
#[doc(hidden)]
|
||||
pub prog: Program
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Copy)]
|
||||
pub struct ExNative {
|
||||
#[doc(hidden)]
|
||||
pub original: &'static str,
|
||||
#[doc(hidden)]
|
||||
pub names: &'static &'static [Option<&'static str>],
|
||||
#[doc(hidden)]
|
||||
pub prog: fn(MatchKind, &str, uint, uint) -> Vec<Option<uint>>
|
||||
}
|
||||
|
||||
impl Clone for ExNative {
|
||||
fn clone(&self) -> ExNative {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::String for Regex {
|
||||
/// Shows the original regular expression.
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::String::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Regex {
|
||||
/// Compiles a dynamic regular expression. Once compiled, it can be
|
||||
/// used repeatedly to search, split or replace text in a string.
|
||||
///
|
||||
/// When possible, you should prefer the `regex!` macro since it is
|
||||
/// safer and always faster.
|
||||
///
|
||||
/// If an invalid expression is given, then an error is returned.
|
||||
pub fn new(re: &str) -> Result<Regex, parse::Error> {
|
||||
let ast = try!(parse::parse(re));
|
||||
let (prog, names) = Program::new(ast);
|
||||
Ok(Dynamic(ExDynamic {
|
||||
original: re.to_string(),
|
||||
names: names,
|
||||
prog: prog,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Returns true if and only if the regex matches the string given.
|
||||
pub fn is_match(&self, text: &str) -> bool {
|
||||
has_match(&exec(self, Exists, text))
|
||||
}
|
||||
|
||||
/// Returns the start and end byte range of the leftmost-first match in
|
||||
/// `text`. If no match exists, then `None` is returned.
|
||||
pub fn find(&self, text: &str) -> Option<(uint, uint)> {
|
||||
let caps = exec(self, Location, text);
|
||||
if has_match(&caps) {
|
||||
Some((caps[0].unwrap(), caps[1].unwrap()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator for each successive non-overlapping match in
|
||||
/// `text`, returning the start and end byte indices with respect to
|
||||
/// `text`.
|
||||
pub fn find_iter<'r, 't>(&'r self, text: &'t str) -> FindMatches<'r, 't> {
|
||||
FindMatches {
|
||||
re: self,
|
||||
search: text,
|
||||
last_end: 0,
|
||||
last_match: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the capture groups corresponding to the leftmost-first
|
||||
/// match in `text`. Capture group `0` always corresponds to the entire
|
||||
/// match. If no match is found, then `None` is returned.
|
||||
///
|
||||
/// You should only use `captures` if you need access to submatches.
|
||||
/// Otherwise, `find` is faster for discovering the location of the overall
|
||||
/// match.
|
||||
pub fn captures<'t>(&self, text: &'t str) -> Option<Captures<'t>> {
|
||||
let caps = exec(self, Submatches, text);
|
||||
Captures::new(self, text, caps)
|
||||
}
|
||||
|
||||
/// Returns an iterator over all the non-overlapping capture groups matched
|
||||
/// in `text`. This is operationally the same as `find_iter` (except it
|
||||
/// yields information about submatches).
|
||||
pub fn captures_iter<'r, 't>(&'r self, text: &'t str)
|
||||
-> FindCaptures<'r, 't> {
|
||||
FindCaptures {
|
||||
re: self,
|
||||
search: text,
|
||||
last_match: None,
|
||||
last_end: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator of substrings of `text` delimited by a match
|
||||
/// of the regular expression.
|
||||
/// Namely, each element of the iterator corresponds to text that *isn't*
|
||||
/// matched by the regular expression.
|
||||
///
|
||||
/// This method will *not* copy the text given.
|
||||
pub fn split<'r, 't>(&'r self, text: &'t str) -> RegexSplits<'r, 't> {
|
||||
RegexSplits {
|
||||
finder: self.find_iter(text),
|
||||
last: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator of at most `limit` substrings of `text` delimited
|
||||
/// by a match of the regular expression. (A `limit` of `0` will return no
|
||||
/// substrings.)
|
||||
/// Namely, each element of the iterator corresponds to text that *isn't*
|
||||
/// matched by the regular expression.
|
||||
/// The remainder of the string that is not split will be the last element
|
||||
/// in the iterator.
|
||||
///
|
||||
/// This method will *not* copy the text given.
|
||||
pub fn splitn<'r, 't>(&'r self, text: &'t str, limit: uint)
|
||||
-> RegexSplitsN<'r, 't> {
|
||||
RegexSplitsN {
|
||||
splits: self.split(text),
|
||||
cur: 0,
|
||||
limit: limit,
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces the leftmost-first match with the replacement provided.
|
||||
/// The replacement can be a regular string (where `$N` and `$name` are
|
||||
/// expanded to match capture groups) or a function that takes the matches'
|
||||
/// `Captures` and returns the replaced string.
|
||||
///
|
||||
/// If no match is found, then a copy of the string is returned unchanged.
|
||||
pub fn replace<R: Replacer>(&self, text: &str, rep: R) -> String {
|
||||
self.replacen(text, 1, rep)
|
||||
}
|
||||
|
||||
/// Replaces all non-overlapping matches in `text` with the
|
||||
/// replacement provided. This is the same as calling `replacen` with
|
||||
/// `limit` set to `0`.
|
||||
///
|
||||
/// See the documentation for `replace` for details on how to access
|
||||
/// submatches in the replacement string.
|
||||
pub fn replace_all<R: Replacer>(&self, text: &str, rep: R) -> String {
|
||||
self.replacen(text, 0, rep)
|
||||
}
|
||||
|
||||
/// Replaces at most `limit` non-overlapping matches in `text` with the
|
||||
/// replacement provided. If `limit` is 0, then all non-overlapping matches
|
||||
/// are replaced.
|
||||
///
|
||||
/// See the documentation for `replace` for details on how to access
|
||||
/// submatches in the replacement string.
|
||||
pub fn replacen<R: Replacer>
|
||||
(&self, text: &str, limit: uint, mut rep: R) -> String {
|
||||
let mut new = String::with_capacity(text.len());
|
||||
let mut last_match = 0u;
|
||||
|
||||
for (i, cap) in self.captures_iter(text).enumerate() {
|
||||
// It'd be nicer to use the 'take' iterator instead, but it seemed
|
||||
// awkward given that '0' => no limit.
|
||||
if limit > 0 && i >= limit {
|
||||
break
|
||||
}
|
||||
|
||||
let (s, e) = cap.pos(0).unwrap(); // captures only reports matches
|
||||
new.push_str(&text[last_match..s]);
|
||||
new.push_str(&rep.reg_replace(&cap)[]);
|
||||
last_match = e;
|
||||
}
|
||||
new.push_str(&text[last_match..text.len()]);
|
||||
return new;
|
||||
}
|
||||
|
||||
/// Returns the original string of this regex.
|
||||
pub fn as_str<'a>(&'a self) -> &'a str {
|
||||
match *self {
|
||||
Dynamic(ExDynamic { ref original, .. }) => &original[],
|
||||
Native(ExNative { ref original, .. }) => &original[],
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn names_iter<'a>(&'a self) -> NamesIter<'a> {
|
||||
match *self {
|
||||
Native(ref n) => NamesIterNative(n.names.iter()),
|
||||
Dynamic(ref d) => NamesIterDynamic(d.names.iter())
|
||||
}
|
||||
}
|
||||
|
||||
fn names_len(&self) -> uint {
|
||||
match *self {
|
||||
Native(ref n) => n.names.len(),
|
||||
Dynamic(ref d) => d.names.len()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum NamesIter<'a> {
|
||||
NamesIterNative(::std::slice::Iter<'a, Option<&'static str>>),
|
||||
NamesIterDynamic(::std::slice::Iter<'a, Option<String>>)
|
||||
}
|
||||
|
||||
impl<'a> Iterator for NamesIter<'a> {
|
||||
type Item = Option<String>;
|
||||
|
||||
fn next(&mut self) -> Option<Option<String>> {
|
||||
match *self {
|
||||
NamesIterNative(ref mut i) => i.next().map(|x| x.map(|s| s.to_string())),
|
||||
NamesIterDynamic(ref mut i) => i.next().map(|x| x.as_ref().map(|s| s.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// NoExpand indicates literal string replacement.
|
||||
///
|
||||
/// It can be used with `replace` and `replace_all` to do a literal
|
||||
/// string replacement without expanding `$name` to their corresponding
|
||||
/// capture groups.
|
||||
///
|
||||
/// `'r` is the lifetime of the literal text.
|
||||
pub struct NoExpand<'t>(pub &'t str);
|
||||
|
||||
/// Replacer describes types that can be used to replace matches in a string.
|
||||
pub trait Replacer {
|
||||
/// Returns a possibly owned string that is used to replace the match
|
||||
/// corresponding to the `caps` capture group.
|
||||
///
|
||||
/// The `'a` lifetime refers to the lifetime of a borrowed string when
|
||||
/// a new owned string isn't needed (e.g., for `NoExpand`).
|
||||
fn reg_replace<'a>(&'a mut self, caps: &Captures) -> CowString<'a>;
|
||||
}
|
||||
|
||||
impl<'t> Replacer for NoExpand<'t> {
|
||||
fn reg_replace<'a>(&'a mut self, _: &Captures) -> CowString<'a> {
|
||||
let NoExpand(s) = *self;
|
||||
s.into_cow()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t> Replacer for &'t str {
|
||||
fn reg_replace<'a>(&'a mut self, caps: &Captures) -> CowString<'a> {
|
||||
caps.expand(*self).into_cow()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Replacer for F where F: FnMut(&Captures) -> String {
|
||||
fn reg_replace<'a>(&'a mut self, caps: &Captures) -> CowString<'a> {
|
||||
(*self)(caps).into_cow()
|
||||
}
|
||||
}
|
||||
|
||||
/// Yields all substrings delimited by a regular expression match.
|
||||
///
|
||||
/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
|
||||
/// of the string being split.
|
||||
#[derive(Clone)]
|
||||
pub struct RegexSplits<'r, 't> {
|
||||
finder: FindMatches<'r, 't>,
|
||||
last: uint,
|
||||
}
|
||||
|
||||
impl<'r, 't> Iterator for RegexSplits<'r, 't> {
|
||||
type Item = &'t str;
|
||||
|
||||
fn next(&mut self) -> Option<&'t str> {
|
||||
let text = self.finder.search;
|
||||
match self.finder.next() {
|
||||
None => {
|
||||
if self.last >= text.len() {
|
||||
None
|
||||
} else {
|
||||
let s = &text[self.last..text.len()];
|
||||
self.last = text.len();
|
||||
Some(s)
|
||||
}
|
||||
}
|
||||
Some((s, e)) => {
|
||||
let matched = &text[self.last..s];
|
||||
self.last = e;
|
||||
Some(matched)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Yields at most `N` substrings delimited by a regular expression match.
|
||||
///
|
||||
/// The last substring will be whatever remains after splitting.
|
||||
///
|
||||
/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
|
||||
/// of the string being split.
|
||||
#[derive(Clone)]
|
||||
pub struct RegexSplitsN<'r, 't> {
|
||||
splits: RegexSplits<'r, 't>,
|
||||
cur: uint,
|
||||
limit: uint,
|
||||
}
|
||||
|
||||
impl<'r, 't> Iterator for RegexSplitsN<'r, 't> {
|
||||
type Item = &'t str;
|
||||
|
||||
fn next(&mut self) -> Option<&'t str> {
|
||||
let text = self.splits.finder.search;
|
||||
if self.cur >= self.limit {
|
||||
None
|
||||
} else {
|
||||
self.cur += 1;
|
||||
if self.cur >= self.limit {
|
||||
Some(&text[self.splits.last..text.len()])
|
||||
} else {
|
||||
self.splits.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Captures represents a group of captured strings for a single match.
|
||||
///
|
||||
/// The 0th capture always corresponds to the entire match. Each subsequent
|
||||
/// index corresponds to the next capture group in the regex.
|
||||
/// If a capture group is named, then the matched string is *also* available
|
||||
/// via the `name` method. (Note that the 0th capture is always unnamed and so
|
||||
/// must be accessed with the `at` method.)
|
||||
///
|
||||
/// Positions returned from a capture group are always byte indices.
|
||||
///
|
||||
/// `'t` is the lifetime of the matched text.
|
||||
pub struct Captures<'t> {
|
||||
text: &'t str,
|
||||
locs: CaptureLocs,
|
||||
named: Option<HashMap<String, uint>>,
|
||||
}
|
||||
|
||||
impl<'t> Captures<'t> {
|
||||
fn new(re: &Regex, search: &'t str, locs: CaptureLocs)
|
||||
-> Option<Captures<'t>> {
|
||||
if !has_match(&locs) {
|
||||
return None
|
||||
}
|
||||
|
||||
let named =
|
||||
if re.names_len() == 0 {
|
||||
None
|
||||
} else {
|
||||
let mut named = HashMap::new();
|
||||
for (i, name) in re.names_iter().enumerate() {
|
||||
match name {
|
||||
None => {},
|
||||
Some(name) => {
|
||||
named.insert(name, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(named)
|
||||
};
|
||||
Some(Captures {
|
||||
text: search,
|
||||
locs: locs,
|
||||
named: named,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the start and end positions of the Nth capture group.
|
||||
/// Returns `None` if `i` is not a valid capture group or if the capture
|
||||
/// group did not match anything.
|
||||
/// The positions returned are *always* byte indices with respect to the
|
||||
/// original string matched.
|
||||
pub fn pos(&self, i: uint) -> Option<(uint, uint)> {
|
||||
let (s, e) = (i * 2, i * 2 + 1);
|
||||
if e >= self.locs.len() || self.locs[s].is_none() {
|
||||
// VM guarantees that each pair of locations are both Some or None.
|
||||
return None
|
||||
}
|
||||
Some((self.locs[s].unwrap(), self.locs[e].unwrap()))
|
||||
}
|
||||
|
||||
/// Returns the matched string for the capture group `i`. If `i` isn't
|
||||
/// a valid capture group or didn't match anything, then `None` is
|
||||
/// returned.
|
||||
pub fn at(&self, i: uint) -> Option<&'t str> {
|
||||
match self.pos(i) {
|
||||
None => None,
|
||||
Some((s, e)) => Some(self.text.slice(s, e))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the matched string for the capture group named `name`. If
|
||||
/// `name` isn't a valid capture group or didn't match anything, then
|
||||
/// `None` is returned.
|
||||
pub fn name(&self, name: &str) -> Option<&'t str> {
|
||||
match self.named {
|
||||
None => None,
|
||||
Some(ref h) => {
|
||||
match h.get(name) {
|
||||
None => None,
|
||||
Some(i) => self.at(*i),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an iterator of all the capture groups in order of appearance
|
||||
/// in the regular expression.
|
||||
pub fn iter(&'t self) -> SubCaptures<'t> {
|
||||
SubCaptures { idx: 0, caps: self, }
|
||||
}
|
||||
|
||||
/// Creates an iterator of all the capture group positions in order of
|
||||
/// appearance in the regular expression. Positions are byte indices
|
||||
/// in terms of the original string matched.
|
||||
pub fn iter_pos(&'t self) -> SubCapturesPos<'t> {
|
||||
SubCapturesPos { idx: 0, caps: self, }
|
||||
}
|
||||
|
||||
/// Expands all instances of `$name` in `text` to the corresponding capture
|
||||
/// group `name`.
|
||||
///
|
||||
/// `name` may be an integer corresponding to the index of the
|
||||
/// capture group (counted by order of opening parenthesis where `0` is the
|
||||
/// entire match) or it can be a name (consisting of letters, digits or
|
||||
/// underscores) corresponding to a named capture group.
|
||||
///
|
||||
/// If `name` isn't a valid capture group (whether the name doesn't exist or
|
||||
/// isn't a valid index), then it is replaced with the empty string.
|
||||
///
|
||||
/// To write a literal `$` use `$$`.
|
||||
pub fn expand(&self, text: &str) -> String {
|
||||
// How evil can you get?
|
||||
// FIXME: Don't use regexes for this. It's completely unnecessary.
|
||||
let re = Regex::new(r"(^|[^$]|\b)\$(\w+)").unwrap();
|
||||
let text = re.replace_all(text, |&mut: refs: &Captures| -> String {
|
||||
let pre = refs.at(1).unwrap_or("");
|
||||
let name = refs.at(2).unwrap_or("");
|
||||
format!("{}{}", pre,
|
||||
match name.parse::<uint>() {
|
||||
None => self.name(name).unwrap_or("").to_string(),
|
||||
Some(i) => self.at(i).unwrap_or("").to_string(),
|
||||
})
|
||||
});
|
||||
let re = Regex::new(r"\$\$").unwrap();
|
||||
re.replace_all(&text[], NoExpand("$"))
|
||||
}
|
||||
|
||||
/// Returns the number of captured groups.
|
||||
#[inline]
|
||||
pub fn len(&self) -> uint { self.locs.len() / 2 }
|
||||
|
||||
/// Returns if there are no captured groups.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
}
|
||||
|
||||
/// An iterator over capture groups for a particular match of a regular
|
||||
/// expression.
|
||||
///
|
||||
/// `'t` is the lifetime of the matched text.
|
||||
#[derive(Clone)]
|
||||
pub struct SubCaptures<'t> {
|
||||
idx: uint,
|
||||
caps: &'t Captures<'t>,
|
||||
}
|
||||
|
||||
impl<'t> Iterator for SubCaptures<'t> {
|
||||
type Item = &'t str;
|
||||
|
||||
fn next(&mut self) -> Option<&'t str> {
|
||||
if self.idx < self.caps.len() {
|
||||
self.idx += 1;
|
||||
Some(self.caps.at(self.idx - 1).unwrap_or(""))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over capture group positions for a particular match of a
|
||||
/// regular expression.
|
||||
///
|
||||
/// Positions are byte indices in terms of the original string matched.
|
||||
///
|
||||
/// `'t` is the lifetime of the matched text.
|
||||
#[derive(Clone)]
|
||||
pub struct SubCapturesPos<'t> {
|
||||
idx: uint,
|
||||
caps: &'t Captures<'t>,
|
||||
}
|
||||
|
||||
impl<'t> Iterator for SubCapturesPos<'t> {
|
||||
type Item = Option<(uint, uint)>;
|
||||
|
||||
fn next(&mut self) -> Option<Option<(uint, uint)>> {
|
||||
if self.idx < self.caps.len() {
|
||||
self.idx += 1;
|
||||
Some(self.caps.pos(self.idx - 1))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that yields all non-overlapping capture groups matching a
|
||||
/// particular regular expression.
|
||||
///
|
||||
/// The iterator stops when no more matches can be found.
|
||||
///
|
||||
/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
|
||||
/// of the matched string.
|
||||
#[derive(Clone)]
|
||||
pub struct FindCaptures<'r, 't> {
|
||||
re: &'r Regex,
|
||||
search: &'t str,
|
||||
last_match: Option<uint>,
|
||||
last_end: uint,
|
||||
}
|
||||
|
||||
impl<'r, 't> Iterator for FindCaptures<'r, 't> {
|
||||
type Item = Captures<'t>;
|
||||
|
||||
fn next(&mut self) -> Option<Captures<'t>> {
|
||||
if self.last_end > self.search.len() {
|
||||
return None
|
||||
}
|
||||
|
||||
let caps = exec_slice(self.re, Submatches, self.search,
|
||||
self.last_end, self.search.len());
|
||||
let (s, e) =
|
||||
if !has_match(&caps) {
|
||||
return None
|
||||
} else {
|
||||
(caps[0].unwrap(), caps[1].unwrap())
|
||||
};
|
||||
|
||||
// Don't accept empty matches immediately following a match.
|
||||
// i.e., no infinite loops please.
|
||||
if e == s && Some(self.last_end) == self.last_match {
|
||||
self.last_end += 1;
|
||||
return self.next()
|
||||
}
|
||||
self.last_end = e;
|
||||
self.last_match = Some(self.last_end);
|
||||
Captures::new(self.re, self.search, caps)
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over all non-overlapping matches for a particular string.
|
||||
///
|
||||
/// The iterator yields a tuple of integers corresponding to the start and end
|
||||
/// of the match. The indices are byte offsets. The iterator stops when no more
|
||||
/// matches can be found.
|
||||
///
|
||||
/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
|
||||
/// of the matched string.
|
||||
#[derive(Clone)]
|
||||
pub struct FindMatches<'r, 't> {
|
||||
re: &'r Regex,
|
||||
search: &'t str,
|
||||
last_match: Option<uint>,
|
||||
last_end: uint,
|
||||
}
|
||||
|
||||
impl<'r, 't> Iterator for FindMatches<'r, 't> {
|
||||
type Item = (uint, uint);
|
||||
|
||||
fn next(&mut self) -> Option<(uint, uint)> {
|
||||
if self.last_end > self.search.len() {
|
||||
return None
|
||||
}
|
||||
|
||||
let caps = exec_slice(self.re, Location, self.search,
|
||||
self.last_end, self.search.len());
|
||||
let (s, e) =
|
||||
if !has_match(&caps) {
|
||||
return None
|
||||
} else {
|
||||
(caps[0].unwrap(), caps[1].unwrap())
|
||||
};
|
||||
|
||||
// Don't accept empty matches immediately following a match.
|
||||
// i.e., no infinite loops please.
|
||||
if e == s && Some(self.last_end) == self.last_match {
|
||||
self.last_end += 1;
|
||||
return self.next()
|
||||
}
|
||||
self.last_end = e;
|
||||
self.last_match = Some(self.last_end);
|
||||
Some((s, e))
|
||||
}
|
||||
}
|
||||
|
||||
fn exec(re: &Regex, which: MatchKind, input: &str) -> CaptureLocs {
|
||||
exec_slice(re, which, input, 0, input.len())
|
||||
}
|
||||
|
||||
fn exec_slice(re: &Regex, which: MatchKind,
|
||||
input: &str, s: uint, e: uint) -> CaptureLocs {
|
||||
match *re {
|
||||
Dynamic(ExDynamic { ref prog, .. }) => vm::run(which, prog, input, s, e),
|
||||
Native(ExNative { ref prog, .. }) => (*prog)(which, input, s, e),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_match(caps: &CaptureLocs) -> bool {
|
||||
caps.len() >= 2 && caps[0].is_some() && caps[1].is_some()
|
||||
}
|
@ -1,183 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::rand::{Rng, thread_rng};
|
||||
use stdtest::Bencher;
|
||||
use std::iter::repeat;
|
||||
|
||||
use regex::{Regex, NoExpand};
|
||||
|
||||
fn bench_assert_match(b: &mut Bencher, re: Regex, text: &str) {
|
||||
b.iter(|| if !re.is_match(text) { panic!("no match") });
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn no_exponential(b: &mut Bencher) {
|
||||
let n = 100;
|
||||
let re = Regex::new(format!("{}{}",
|
||||
repeat("a?").take(n).collect::<String>(),
|
||||
repeat("a").take(n).collect::<String>()).as_slice()).unwrap();
|
||||
let text = repeat("a").take(n).collect::<String>();
|
||||
bench_assert_match(b, re, text.as_slice());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn literal(b: &mut Bencher) {
|
||||
let re = regex!("y");
|
||||
let text = format!("{}y", repeat("x").take(50).collect::<String>());
|
||||
bench_assert_match(b, re, text.as_slice());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn not_literal(b: &mut Bencher) {
|
||||
let re = regex!(".y");
|
||||
let text = format!("{}y", repeat("x").take(50).collect::<String>());
|
||||
bench_assert_match(b, re, text.as_slice());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn match_class(b: &mut Bencher) {
|
||||
let re = regex!("[abcdw]");
|
||||
let text = format!("{}w", repeat("xxxx").take(20).collect::<String>());
|
||||
bench_assert_match(b, re, text.as_slice());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn match_class_in_range(b: &mut Bencher) {
|
||||
// 'b' is between 'a' and 'c', so the class range checking doesn't help.
|
||||
let re = regex!("[ac]");
|
||||
let text = format!("{}c", repeat("bbbb").take(20).collect::<String>());
|
||||
bench_assert_match(b, re, text.as_slice());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn replace_all(b: &mut Bencher) {
|
||||
let re = regex!("[cjrw]");
|
||||
let text = "abcdefghijklmnopqrstuvwxyz";
|
||||
// FIXME: This isn't using the $name expand stuff.
|
||||
// It's possible RE2/Go is using it, but currently, the expand in this
|
||||
// crate is actually compiling a regex, so it's incredibly slow.
|
||||
b.iter(|| re.replace_all(text, NoExpand("")));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn anchored_literal_short_non_match(b: &mut Bencher) {
|
||||
let re = regex!("^zbc(d|e)");
|
||||
let text = "abcdefghijklmnopqrstuvwxyz";
|
||||
b.iter(|| re.is_match(text));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn anchored_literal_long_non_match(b: &mut Bencher) {
|
||||
let re = regex!("^zbc(d|e)");
|
||||
let text = repeat("abcdefghijklmnopqrstuvwxyz").take(15).collect::<String>();
|
||||
b.iter(|| re.is_match(text.as_slice()));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn anchored_literal_short_match(b: &mut Bencher) {
|
||||
let re = regex!("^.bc(d|e)");
|
||||
let text = "abcdefghijklmnopqrstuvwxyz";
|
||||
b.iter(|| re.is_match(text));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn anchored_literal_long_match(b: &mut Bencher) {
|
||||
let re = regex!("^.bc(d|e)");
|
||||
let text = repeat("abcdefghijklmnopqrstuvwxyz").take(15).collect::<String>();
|
||||
b.iter(|| re.is_match(text.as_slice()));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn one_pass_short_a(b: &mut Bencher) {
|
||||
let re = regex!("^.bc(d|e)*$");
|
||||
let text = "abcddddddeeeededd";
|
||||
b.iter(|| re.is_match(text));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn one_pass_short_a_not(b: &mut Bencher) {
|
||||
let re = regex!(".bc(d|e)*$");
|
||||
let text = "abcddddddeeeededd";
|
||||
b.iter(|| re.is_match(text));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn one_pass_short_b(b: &mut Bencher) {
|
||||
let re = regex!("^.bc(?:d|e)*$");
|
||||
let text = "abcddddddeeeededd";
|
||||
b.iter(|| re.is_match(text));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn one_pass_short_b_not(b: &mut Bencher) {
|
||||
let re = regex!(".bc(?:d|e)*$");
|
||||
let text = "abcddddddeeeededd";
|
||||
b.iter(|| re.is_match(text));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn one_pass_long_prefix(b: &mut Bencher) {
|
||||
let re = regex!("^abcdefghijklmnopqrstuvwxyz.*$");
|
||||
let text = "abcdefghijklmnopqrstuvwxyz";
|
||||
b.iter(|| re.is_match(text));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn one_pass_long_prefix_not(b: &mut Bencher) {
|
||||
let re = regex!("^.bcdefghijklmnopqrstuvwxyz.*$");
|
||||
let text = "abcdefghijklmnopqrstuvwxyz";
|
||||
b.iter(|| re.is_match(text));
|
||||
}
|
||||
|
||||
macro_rules! throughput {
|
||||
($name:ident, $regex:expr, $size:expr) => (
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let text = gen_text($size);
|
||||
b.bytes = $size;
|
||||
b.iter(|| if $regex.is_match(text.as_slice()) { panic!("match") });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
fn easy0() -> Regex { regex!("ABCDEFGHIJKLMNOPQRSTUVWXYZ$") }
|
||||
fn easy1() -> Regex { regex!("A[AB]B[BC]C[CD]D[DE]E[EF]F[FG]G[GH]H[HI]I[IJ]J$") }
|
||||
fn medium() -> Regex { regex!("[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$") }
|
||||
fn hard() -> Regex { regex!("[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$") }
|
||||
|
||||
fn gen_text(n: uint) -> String {
|
||||
let mut rng = thread_rng();
|
||||
let mut bytes = rng.gen_ascii_chars().map(|n| n as u8).take(n)
|
||||
.collect::<Vec<u8>>();
|
||||
for (i, b) in bytes.iter_mut().enumerate() {
|
||||
if i % 20 == 0 {
|
||||
*b = b'\n'
|
||||
}
|
||||
}
|
||||
String::from_utf8(bytes).unwrap()
|
||||
}
|
||||
|
||||
throughput!{easy0_32, easy0(), 32}
|
||||
throughput!{easy0_1K, easy0(), 1<<10}
|
||||
throughput!{easy0_32K, easy0(), 32<<10}
|
||||
|
||||
throughput!{easy1_32, easy1(), 32}
|
||||
throughput!{easy1_1K, easy1(), 1<<10}
|
||||
throughput!{easy1_32K, easy1(), 32<<10}
|
||||
|
||||
throughput!{medium_32, medium(), 32}
|
||||
throughput!{medium_1K, medium(), 1<<10}
|
||||
throughput!{medium_32K,medium(), 32<<10}
|
||||
|
||||
throughput!{hard_32, hard(), 32}
|
||||
throughput!{hard_1K, hard(), 1<<10}
|
||||
throughput!{hard_32K,hard(), 32<<10}
|
@ -1,373 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-tidy-linelength
|
||||
|
||||
// DO NOT EDIT. Automatically generated by 'src/etc/regex-match-tests'
|
||||
// on 2014-04-23 01:33:36.539280.
|
||||
|
||||
// Tests from basic.dat
|
||||
mat!{match_basic_3, r"abracadabra$", r"abracadabracadabra", Some((7, 18))}
|
||||
mat!{match_basic_4, r"a...b", r"abababbb", Some((2, 7))}
|
||||
mat!{match_basic_5, r"XXXXXX", r"..XXXXXX", Some((2, 8))}
|
||||
mat!{match_basic_6, r"\)", r"()", Some((1, 2))}
|
||||
mat!{match_basic_7, r"a]", r"a]a", Some((0, 2))}
|
||||
mat!{match_basic_9, r"\}", r"}", Some((0, 1))}
|
||||
mat!{match_basic_10, r"\]", r"]", Some((0, 1))}
|
||||
mat!{match_basic_12, r"]", r"]", Some((0, 1))}
|
||||
mat!{match_basic_15, r"^a", r"ax", Some((0, 1))}
|
||||
mat!{match_basic_16, r"\^a", r"a^a", Some((1, 3))}
|
||||
mat!{match_basic_17, r"a\^", r"a^", Some((0, 2))}
|
||||
mat!{match_basic_18, r"a$", r"aa", Some((1, 2))}
|
||||
mat!{match_basic_19, r"a\$", r"a$", Some((0, 2))}
|
||||
mat!{match_basic_20, r"^$", r"", Some((0, 0))}
|
||||
mat!{match_basic_21, r"$^", r"", Some((0, 0))}
|
||||
mat!{match_basic_22, r"a($)", r"aa", Some((1, 2)), Some((2, 2))}
|
||||
mat!{match_basic_23, r"a*(^a)", r"aa", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_basic_24, r"(..)*(...)*", r"a", Some((0, 0))}
|
||||
mat!{match_basic_25, r"(..)*(...)*", r"abcd", Some((0, 4)), Some((2, 4))}
|
||||
mat!{match_basic_26, r"(ab|a)(bc|c)", r"abc", Some((0, 3)), Some((0, 2)), Some((2, 3))}
|
||||
mat!{match_basic_27, r"(ab)c|abc", r"abc", Some((0, 3)), Some((0, 2))}
|
||||
mat!{match_basic_28, r"a{0}b", r"ab", Some((1, 2))}
|
||||
mat!{match_basic_29, r"(a*)(b?)(b+)b{3}", r"aaabbbbbbb", Some((0, 10)), Some((0, 3)), Some((3, 4)), Some((4, 7))}
|
||||
mat!{match_basic_30, r"(a*)(b{0,1})(b{1,})b{3}", r"aaabbbbbbb", Some((0, 10)), Some((0, 3)), Some((3, 4)), Some((4, 7))}
|
||||
mat!{match_basic_32, r"((a|a)|a)", r"a", Some((0, 1)), Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_basic_33, r"(a*)(a|aa)", r"aaaa", Some((0, 4)), Some((0, 3)), Some((3, 4))}
|
||||
mat!{match_basic_34, r"a*(a.|aa)", r"aaaa", Some((0, 4)), Some((2, 4))}
|
||||
mat!{match_basic_35, r"a(b)|c(d)|a(e)f", r"aef", Some((0, 3)), None, None, Some((1, 2))}
|
||||
mat!{match_basic_36, r"(a|b)?.*", r"b", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_basic_37, r"(a|b)c|a(b|c)", r"ac", Some((0, 2)), Some((0, 1))}
|
||||
mat!{match_basic_38, r"(a|b)c|a(b|c)", r"ab", Some((0, 2)), None, Some((1, 2))}
|
||||
mat!{match_basic_39, r"(a|b)*c|(a|ab)*c", r"abc", Some((0, 3)), Some((1, 2))}
|
||||
mat!{match_basic_40, r"(a|b)*c|(a|ab)*c", r"xc", Some((1, 2))}
|
||||
mat!{match_basic_41, r"(.a|.b).*|.*(.a|.b)", r"xa", Some((0, 2)), Some((0, 2))}
|
||||
mat!{match_basic_42, r"a?(ab|ba)ab", r"abab", Some((0, 4)), Some((0, 2))}
|
||||
mat!{match_basic_43, r"a?(ac{0}b|ba)ab", r"abab", Some((0, 4)), Some((0, 2))}
|
||||
mat!{match_basic_44, r"ab|abab", r"abbabab", Some((0, 2))}
|
||||
mat!{match_basic_45, r"aba|bab|bba", r"baaabbbaba", Some((5, 8))}
|
||||
mat!{match_basic_46, r"aba|bab", r"baaabbbaba", Some((6, 9))}
|
||||
mat!{match_basic_47, r"(aa|aaa)*|(a|aaaaa)", r"aa", Some((0, 2)), Some((0, 2))}
|
||||
mat!{match_basic_48, r"(a.|.a.)*|(a|.a...)", r"aa", Some((0, 2)), Some((0, 2))}
|
||||
mat!{match_basic_49, r"ab|a", r"xabc", Some((1, 3))}
|
||||
mat!{match_basic_50, r"ab|a", r"xxabc", Some((2, 4))}
|
||||
mat!{match_basic_51, r"(?i)(Ab|cD)*", r"aBcD", Some((0, 4)), Some((2, 4))}
|
||||
mat!{match_basic_52, r"[^-]", r"--a", Some((2, 3))}
|
||||
mat!{match_basic_53, r"[a-]*", r"--a", Some((0, 3))}
|
||||
mat!{match_basic_54, r"[a-m-]*", r"--amoma--", Some((0, 4))}
|
||||
mat!{match_basic_55, r":::1:::0:|:::1:1:0:", r":::0:::1:::1:::0:", Some((8, 17))}
|
||||
mat!{match_basic_56, r":::1:::0:|:::1:1:1:", r":::0:::1:::1:::0:", Some((8, 17))}
|
||||
mat!{match_basic_57, r"[[:upper:]]", r"A", Some((0, 1))}
|
||||
mat!{match_basic_58, r"[[:lower:]]+", r"`az{", Some((1, 3))}
|
||||
mat!{match_basic_59, r"[[:upper:]]+", r"@AZ[", Some((1, 3))}
|
||||
mat!{match_basic_65, r"
|
||||
", r"
|
||||
", Some((0, 1))}
|
||||
mat!{match_basic_66, r"
|
||||
", r"
|
||||
", Some((0, 1))}
|
||||
mat!{match_basic_67, r"[^a]", r"
|
||||
", Some((0, 1))}
|
||||
mat!{match_basic_68, r"
|
||||
a", r"
|
||||
a", Some((0, 2))}
|
||||
mat!{match_basic_69, r"(a)(b)(c)", r"abc", Some((0, 3)), Some((0, 1)), Some((1, 2)), Some((2, 3))}
|
||||
mat!{match_basic_70, r"xxx", r"xxx", Some((0, 3))}
|
||||
mat!{match_basic_71, r"(^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)", r"feb 6,", Some((0, 6))}
|
||||
mat!{match_basic_72, r"(^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)", r"2/7", Some((0, 3))}
|
||||
mat!{match_basic_73, r"(^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)", r"feb 1,Feb 6", Some((5, 11))}
|
||||
mat!{match_basic_74, r"((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))", r"x", Some((0, 1)), Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_basic_75, r"((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))*", r"xx", Some((0, 2)), Some((1, 2)), Some((1, 2))}
|
||||
mat!{match_basic_76, r"a?(ab|ba)*", r"ababababababababababababababababababababababababababababababababababababababababa", Some((0, 81)), Some((79, 81))}
|
||||
mat!{match_basic_77, r"abaa|abbaa|abbbaa|abbbbaa", r"ababbabbbabbbabbbbabbbbaa", Some((18, 25))}
|
||||
mat!{match_basic_78, r"abaa|abbaa|abbbaa|abbbbaa", r"ababbabbbabbbabbbbabaa", Some((18, 22))}
|
||||
mat!{match_basic_79, r"aaac|aabc|abac|abbc|baac|babc|bbac|bbbc", r"baaabbbabac", Some((7, 11))}
|
||||
mat!{match_basic_80, r".*", r"", Some((0, 2))}
|
||||
mat!{match_basic_81, r"aaaa|bbbb|cccc|ddddd|eeeeee|fffffff|gggg|hhhh|iiiii|jjjjj|kkkkk|llll", r"XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa", Some((53, 57))}
|
||||
mat!{match_basic_83, r"a*a*a*a*a*b", r"aaaaaaaaab", Some((0, 10))}
|
||||
mat!{match_basic_84, r"^", r"", Some((0, 0))}
|
||||
mat!{match_basic_85, r"$", r"", Some((0, 0))}
|
||||
mat!{match_basic_86, r"^$", r"", Some((0, 0))}
|
||||
mat!{match_basic_87, r"^a$", r"a", Some((0, 1))}
|
||||
mat!{match_basic_88, r"abc", r"abc", Some((0, 3))}
|
||||
mat!{match_basic_89, r"abc", r"xabcy", Some((1, 4))}
|
||||
mat!{match_basic_90, r"abc", r"ababc", Some((2, 5))}
|
||||
mat!{match_basic_91, r"ab*c", r"abc", Some((0, 3))}
|
||||
mat!{match_basic_92, r"ab*bc", r"abc", Some((0, 3))}
|
||||
mat!{match_basic_93, r"ab*bc", r"abbc", Some((0, 4))}
|
||||
mat!{match_basic_94, r"ab*bc", r"abbbbc", Some((0, 6))}
|
||||
mat!{match_basic_95, r"ab+bc", r"abbc", Some((0, 4))}
|
||||
mat!{match_basic_96, r"ab+bc", r"abbbbc", Some((0, 6))}
|
||||
mat!{match_basic_97, r"ab?bc", r"abbc", Some((0, 4))}
|
||||
mat!{match_basic_98, r"ab?bc", r"abc", Some((0, 3))}
|
||||
mat!{match_basic_99, r"ab?c", r"abc", Some((0, 3))}
|
||||
mat!{match_basic_100, r"^abc$", r"abc", Some((0, 3))}
|
||||
mat!{match_basic_101, r"^abc", r"abcc", Some((0, 3))}
|
||||
mat!{match_basic_102, r"abc$", r"aabc", Some((1, 4))}
|
||||
mat!{match_basic_103, r"^", r"abc", Some((0, 0))}
|
||||
mat!{match_basic_104, r"$", r"abc", Some((3, 3))}
|
||||
mat!{match_basic_105, r"a.c", r"abc", Some((0, 3))}
|
||||
mat!{match_basic_106, r"a.c", r"axc", Some((0, 3))}
|
||||
mat!{match_basic_107, r"a.*c", r"axyzc", Some((0, 5))}
|
||||
mat!{match_basic_108, r"a[bc]d", r"abd", Some((0, 3))}
|
||||
mat!{match_basic_109, r"a[b-d]e", r"ace", Some((0, 3))}
|
||||
mat!{match_basic_110, r"a[b-d]", r"aac", Some((1, 3))}
|
||||
mat!{match_basic_111, r"a[-b]", r"a-", Some((0, 2))}
|
||||
mat!{match_basic_112, r"a[b-]", r"a-", Some((0, 2))}
|
||||
mat!{match_basic_113, r"a]", r"a]", Some((0, 2))}
|
||||
mat!{match_basic_114, r"a[]]b", r"a]b", Some((0, 3))}
|
||||
mat!{match_basic_115, r"a[^bc]d", r"aed", Some((0, 3))}
|
||||
mat!{match_basic_116, r"a[^-b]c", r"adc", Some((0, 3))}
|
||||
mat!{match_basic_117, r"a[^]b]c", r"adc", Some((0, 3))}
|
||||
mat!{match_basic_118, r"ab|cd", r"abc", Some((0, 2))}
|
||||
mat!{match_basic_119, r"ab|cd", r"abcd", Some((0, 2))}
|
||||
mat!{match_basic_120, r"a\(b", r"a(b", Some((0, 3))}
|
||||
mat!{match_basic_121, r"a\(*b", r"ab", Some((0, 2))}
|
||||
mat!{match_basic_122, r"a\(*b", r"a((b", Some((0, 4))}
|
||||
mat!{match_basic_123, r"((a))", r"abc", Some((0, 1)), Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_basic_124, r"(a)b(c)", r"abc", Some((0, 3)), Some((0, 1)), Some((2, 3))}
|
||||
mat!{match_basic_125, r"a+b+c", r"aabbabc", Some((4, 7))}
|
||||
mat!{match_basic_126, r"a*", r"aaa", Some((0, 3))}
|
||||
mat!{match_basic_128, r"(a*)*", r"-", Some((0, 0)), None}
|
||||
mat!{match_basic_129, r"(a*)+", r"-", Some((0, 0)), Some((0, 0))}
|
||||
mat!{match_basic_131, r"(a*|b)*", r"-", Some((0, 0)), None}
|
||||
mat!{match_basic_132, r"(a+|b)*", r"ab", Some((0, 2)), Some((1, 2))}
|
||||
mat!{match_basic_133, r"(a+|b)+", r"ab", Some((0, 2)), Some((1, 2))}
|
||||
mat!{match_basic_134, r"(a+|b)?", r"ab", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_basic_135, r"[^ab]*", r"cde", Some((0, 3))}
|
||||
mat!{match_basic_137, r"(^)*", r"-", Some((0, 0)), None}
|
||||
mat!{match_basic_138, r"a*", r"", Some((0, 0))}
|
||||
mat!{match_basic_139, r"([abc])*d", r"abbbcd", Some((0, 6)), Some((4, 5))}
|
||||
mat!{match_basic_140, r"([abc])*bcd", r"abcd", Some((0, 4)), Some((0, 1))}
|
||||
mat!{match_basic_141, r"a|b|c|d|e", r"e", Some((0, 1))}
|
||||
mat!{match_basic_142, r"(a|b|c|d|e)f", r"ef", Some((0, 2)), Some((0, 1))}
|
||||
mat!{match_basic_144, r"((a*|b))*", r"-", Some((0, 0)), None, None}
|
||||
mat!{match_basic_145, r"abcd*efg", r"abcdefg", Some((0, 7))}
|
||||
mat!{match_basic_146, r"ab*", r"xabyabbbz", Some((1, 3))}
|
||||
mat!{match_basic_147, r"ab*", r"xayabbbz", Some((1, 2))}
|
||||
mat!{match_basic_148, r"(ab|cd)e", r"abcde", Some((2, 5)), Some((2, 4))}
|
||||
mat!{match_basic_149, r"[abhgefdc]ij", r"hij", Some((0, 3))}
|
||||
mat!{match_basic_150, r"(a|b)c*d", r"abcd", Some((1, 4)), Some((1, 2))}
|
||||
mat!{match_basic_151, r"(ab|ab*)bc", r"abc", Some((0, 3)), Some((0, 1))}
|
||||
mat!{match_basic_152, r"a([bc]*)c*", r"abc", Some((0, 3)), Some((1, 3))}
|
||||
mat!{match_basic_153, r"a([bc]*)(c*d)", r"abcd", Some((0, 4)), Some((1, 3)), Some((3, 4))}
|
||||
mat!{match_basic_154, r"a([bc]+)(c*d)", r"abcd", Some((0, 4)), Some((1, 3)), Some((3, 4))}
|
||||
mat!{match_basic_155, r"a([bc]*)(c+d)", r"abcd", Some((0, 4)), Some((1, 2)), Some((2, 4))}
|
||||
mat!{match_basic_156, r"a[bcd]*dcdcde", r"adcdcde", Some((0, 7))}
|
||||
mat!{match_basic_157, r"(ab|a)b*c", r"abc", Some((0, 3)), Some((0, 2))}
|
||||
mat!{match_basic_158, r"((a)(b)c)(d)", r"abcd", Some((0, 4)), Some((0, 3)), Some((0, 1)), Some((1, 2)), Some((3, 4))}
|
||||
mat!{match_basic_159, r"[A-Za-z_][A-Za-z0-9_]*", r"alpha", Some((0, 5))}
|
||||
mat!{match_basic_160, r"^a(bc+|b[eh])g|.h$", r"abh", Some((1, 3))}
|
||||
mat!{match_basic_161, r"(bc+d$|ef*g.|h?i(j|k))", r"effgz", Some((0, 5)), Some((0, 5))}
|
||||
mat!{match_basic_162, r"(bc+d$|ef*g.|h?i(j|k))", r"ij", Some((0, 2)), Some((0, 2)), Some((1, 2))}
|
||||
mat!{match_basic_163, r"(bc+d$|ef*g.|h?i(j|k))", r"reffgz", Some((1, 6)), Some((1, 6))}
|
||||
mat!{match_basic_164, r"(((((((((a)))))))))", r"a", Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_basic_165, r"multiple words", r"multiple words yeah", Some((0, 14))}
|
||||
mat!{match_basic_166, r"(.*)c(.*)", r"abcde", Some((0, 5)), Some((0, 2)), Some((3, 5))}
|
||||
mat!{match_basic_167, r"abcd", r"abcd", Some((0, 4))}
|
||||
mat!{match_basic_168, r"a(bc)d", r"abcd", Some((0, 4)), Some((1, 3))}
|
||||
mat!{match_basic_169, r"a[-]?c", r"ac", Some((0, 3))}
|
||||
mat!{match_basic_170, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Qaddafi", Some((0, 15)), None, Some((10, 12))}
|
||||
mat!{match_basic_171, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Mo'ammar Gadhafi", Some((0, 16)), None, Some((11, 13))}
|
||||
mat!{match_basic_172, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Kaddafi", Some((0, 15)), None, Some((10, 12))}
|
||||
mat!{match_basic_173, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Qadhafi", Some((0, 15)), None, Some((10, 12))}
|
||||
mat!{match_basic_174, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Gadafi", Some((0, 14)), None, Some((10, 11))}
|
||||
mat!{match_basic_175, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Mu'ammar Qadafi", Some((0, 15)), None, Some((11, 12))}
|
||||
mat!{match_basic_176, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Moamar Gaddafi", Some((0, 14)), None, Some((9, 11))}
|
||||
mat!{match_basic_177, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Mu'ammar Qadhdhafi", Some((0, 18)), None, Some((13, 15))}
|
||||
mat!{match_basic_178, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Khaddafi", Some((0, 16)), None, Some((11, 13))}
|
||||
mat!{match_basic_179, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Ghaddafy", Some((0, 16)), None, Some((11, 13))}
|
||||
mat!{match_basic_180, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Ghadafi", Some((0, 15)), None, Some((11, 12))}
|
||||
mat!{match_basic_181, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Ghaddafi", Some((0, 16)), None, Some((11, 13))}
|
||||
mat!{match_basic_182, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muamar Kaddafi", Some((0, 14)), None, Some((9, 11))}
|
||||
mat!{match_basic_183, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Quathafi", Some((0, 16)), None, Some((11, 13))}
|
||||
mat!{match_basic_184, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Gheddafi", Some((0, 16)), None, Some((11, 13))}
|
||||
mat!{match_basic_185, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Moammar Khadafy", Some((0, 15)), None, Some((11, 12))}
|
||||
mat!{match_basic_186, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Moammar Qudhafi", Some((0, 15)), None, Some((10, 12))}
|
||||
mat!{match_basic_187, r"a+(b|c)*d+", r"aabcdd", Some((0, 6)), Some((3, 4))}
|
||||
mat!{match_basic_188, r"^.+$", r"vivi", Some((0, 4))}
|
||||
mat!{match_basic_189, r"^(.+)$", r"vivi", Some((0, 4)), Some((0, 4))}
|
||||
mat!{match_basic_190, r"^([^!.]+).att.com!(.+)$", r"gryphon.att.com!eby", Some((0, 19)), Some((0, 7)), Some((16, 19))}
|
||||
mat!{match_basic_191, r"^([^!]+!)?([^!]+)$", r"bas", Some((0, 3)), None, Some((0, 3))}
|
||||
mat!{match_basic_192, r"^([^!]+!)?([^!]+)$", r"bar!bas", Some((0, 7)), Some((0, 4)), Some((4, 7))}
|
||||
mat!{match_basic_193, r"^([^!]+!)?([^!]+)$", r"foo!bas", Some((0, 7)), Some((0, 4)), Some((4, 7))}
|
||||
mat!{match_basic_194, r"^.+!([^!]+!)([^!]+)$", r"foo!bar!bas", Some((0, 11)), Some((4, 8)), Some((8, 11))}
|
||||
mat!{match_basic_195, r"((foo)|(bar))!bas", r"bar!bas", Some((0, 7)), Some((0, 3)), None, Some((0, 3))}
|
||||
mat!{match_basic_196, r"((foo)|(bar))!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7)), None, Some((4, 7))}
|
||||
mat!{match_basic_197, r"((foo)|(bar))!bas", r"foo!bas", Some((0, 7)), Some((0, 3)), Some((0, 3))}
|
||||
mat!{match_basic_198, r"((foo)|bar)!bas", r"bar!bas", Some((0, 7)), Some((0, 3))}
|
||||
mat!{match_basic_199, r"((foo)|bar)!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7))}
|
||||
mat!{match_basic_200, r"((foo)|bar)!bas", r"foo!bas", Some((0, 7)), Some((0, 3)), Some((0, 3))}
|
||||
mat!{match_basic_201, r"(foo|(bar))!bas", r"bar!bas", Some((0, 7)), Some((0, 3)), Some((0, 3))}
|
||||
mat!{match_basic_202, r"(foo|(bar))!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7)), Some((4, 7))}
|
||||
mat!{match_basic_203, r"(foo|(bar))!bas", r"foo!bas", Some((0, 7)), Some((0, 3))}
|
||||
mat!{match_basic_204, r"(foo|bar)!bas", r"bar!bas", Some((0, 7)), Some((0, 3))}
|
||||
mat!{match_basic_205, r"(foo|bar)!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7))}
|
||||
mat!{match_basic_206, r"(foo|bar)!bas", r"foo!bas", Some((0, 7)), Some((0, 3))}
|
||||
mat!{match_basic_207, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"foo!bar!bas", Some((0, 11)), Some((0, 11)), None, None, Some((4, 8)), Some((8, 11))}
|
||||
mat!{match_basic_208, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"bas", Some((0, 3)), None, Some((0, 3))}
|
||||
mat!{match_basic_209, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"bar!bas", Some((0, 7)), Some((0, 4)), Some((4, 7))}
|
||||
mat!{match_basic_210, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"foo!bar!bas", Some((0, 11)), None, None, Some((4, 8)), Some((8, 11))}
|
||||
mat!{match_basic_211, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"foo!bas", Some((0, 7)), Some((0, 4)), Some((4, 7))}
|
||||
mat!{match_basic_212, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"bas", Some((0, 3)), Some((0, 3)), None, Some((0, 3))}
|
||||
mat!{match_basic_213, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"bar!bas", Some((0, 7)), Some((0, 7)), Some((0, 4)), Some((4, 7))}
|
||||
mat!{match_basic_214, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"foo!bar!bas", Some((0, 11)), Some((0, 11)), None, None, Some((4, 8)), Some((8, 11))}
|
||||
mat!{match_basic_215, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"foo!bas", Some((0, 7)), Some((0, 7)), Some((0, 4)), Some((4, 7))}
|
||||
mat!{match_basic_216, r".*(/XXX).*", r"/XXX", Some((0, 4)), Some((0, 4))}
|
||||
mat!{match_basic_217, r".*(\\XXX).*", r"\XXX", Some((0, 4)), Some((0, 4))}
|
||||
mat!{match_basic_218, r"\\XXX", r"\XXX", Some((0, 4))}
|
||||
mat!{match_basic_219, r".*(/000).*", r"/000", Some((0, 4)), Some((0, 4))}
|
||||
mat!{match_basic_220, r".*(\\000).*", r"\000", Some((0, 4)), Some((0, 4))}
|
||||
mat!{match_basic_221, r"\\000", r"\000", Some((0, 4))}
|
||||
|
||||
// Tests from nullsubexpr.dat
|
||||
mat!{match_nullsubexpr_3, r"(a*)*", r"a", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_5, r"(a*)*", r"x", Some((0, 0)), None}
|
||||
mat!{match_nullsubexpr_6, r"(a*)*", r"aaaaaa", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_7, r"(a*)*", r"aaaaaax", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_8, r"(a*)+", r"a", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_9, r"(a*)+", r"x", Some((0, 0)), Some((0, 0))}
|
||||
mat!{match_nullsubexpr_10, r"(a*)+", r"aaaaaa", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_11, r"(a*)+", r"aaaaaax", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_12, r"(a+)*", r"a", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_13, r"(a+)*", r"x", Some((0, 0))}
|
||||
mat!{match_nullsubexpr_14, r"(a+)*", r"aaaaaa", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_15, r"(a+)*", r"aaaaaax", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_16, r"(a+)+", r"a", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_17, r"(a+)+", r"x", None}
|
||||
mat!{match_nullsubexpr_18, r"(a+)+", r"aaaaaa", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_19, r"(a+)+", r"aaaaaax", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_21, r"([a]*)*", r"a", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_23, r"([a]*)*", r"x", Some((0, 0)), None}
|
||||
mat!{match_nullsubexpr_24, r"([a]*)*", r"aaaaaa", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_25, r"([a]*)*", r"aaaaaax", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_26, r"([a]*)+", r"a", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_27, r"([a]*)+", r"x", Some((0, 0)), Some((0, 0))}
|
||||
mat!{match_nullsubexpr_28, r"([a]*)+", r"aaaaaa", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_29, r"([a]*)+", r"aaaaaax", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_30, r"([^b]*)*", r"a", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_32, r"([^b]*)*", r"b", Some((0, 0)), None}
|
||||
mat!{match_nullsubexpr_33, r"([^b]*)*", r"aaaaaa", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_34, r"([^b]*)*", r"aaaaaab", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_35, r"([ab]*)*", r"a", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_36, r"([ab]*)*", r"aaaaaa", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_37, r"([ab]*)*", r"ababab", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_38, r"([ab]*)*", r"bababa", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_39, r"([ab]*)*", r"b", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_40, r"([ab]*)*", r"bbbbbb", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_41, r"([ab]*)*", r"aaaabcde", Some((0, 5)), Some((0, 5))}
|
||||
mat!{match_nullsubexpr_42, r"([^a]*)*", r"b", Some((0, 1)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_43, r"([^a]*)*", r"bbbbbb", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_45, r"([^a]*)*", r"aaaaaa", Some((0, 0)), None}
|
||||
mat!{match_nullsubexpr_46, r"([^ab]*)*", r"ccccxx", Some((0, 6)), Some((0, 6))}
|
||||
mat!{match_nullsubexpr_48, r"([^ab]*)*", r"ababab", Some((0, 0)), None}
|
||||
mat!{match_nullsubexpr_50, r"((z)+|a)*", r"zabcde", Some((0, 2)), Some((1, 2))}
|
||||
mat!{match_nullsubexpr_69, r"(a*)*(x)", r"x", Some((0, 1)), None, Some((0, 1))}
|
||||
mat!{match_nullsubexpr_70, r"(a*)*(x)", r"ax", Some((0, 2)), Some((0, 1)), Some((1, 2))}
|
||||
mat!{match_nullsubexpr_71, r"(a*)*(x)", r"axa", Some((0, 2)), Some((0, 1)), Some((1, 2))}
|
||||
mat!{match_nullsubexpr_73, r"(a*)+(x)", r"x", Some((0, 1)), Some((0, 0)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_74, r"(a*)+(x)", r"ax", Some((0, 2)), Some((0, 1)), Some((1, 2))}
|
||||
mat!{match_nullsubexpr_75, r"(a*)+(x)", r"axa", Some((0, 2)), Some((0, 1)), Some((1, 2))}
|
||||
mat!{match_nullsubexpr_77, r"(a*){2}(x)", r"x", Some((0, 1)), Some((0, 0)), Some((0, 1))}
|
||||
mat!{match_nullsubexpr_78, r"(a*){2}(x)", r"ax", Some((0, 2)), Some((1, 1)), Some((1, 2))}
|
||||
mat!{match_nullsubexpr_79, r"(a*){2}(x)", r"axa", Some((0, 2)), Some((1, 1)), Some((1, 2))}
|
||||
|
||||
// Tests from repetition.dat
|
||||
mat!{match_repetition_10, r"((..)|(.))", r"", None}
|
||||
mat!{match_repetition_11, r"((..)|(.))((..)|(.))", r"", None}
|
||||
mat!{match_repetition_12, r"((..)|(.))((..)|(.))((..)|(.))", r"", None}
|
||||
mat!{match_repetition_14, r"((..)|(.)){1}", r"", None}
|
||||
mat!{match_repetition_15, r"((..)|(.)){2}", r"", None}
|
||||
mat!{match_repetition_16, r"((..)|(.)){3}", r"", None}
|
||||
mat!{match_repetition_18, r"((..)|(.))*", r"", Some((0, 0))}
|
||||
mat!{match_repetition_20, r"((..)|(.))", r"a", Some((0, 1)), Some((0, 1)), None, Some((0, 1))}
|
||||
mat!{match_repetition_21, r"((..)|(.))((..)|(.))", r"a", None}
|
||||
mat!{match_repetition_22, r"((..)|(.))((..)|(.))((..)|(.))", r"a", None}
|
||||
mat!{match_repetition_24, r"((..)|(.)){1}", r"a", Some((0, 1)), Some((0, 1)), None, Some((0, 1))}
|
||||
mat!{match_repetition_25, r"((..)|(.)){2}", r"a", None}
|
||||
mat!{match_repetition_26, r"((..)|(.)){3}", r"a", None}
|
||||
mat!{match_repetition_28, r"((..)|(.))*", r"a", Some((0, 1)), Some((0, 1)), None, Some((0, 1))}
|
||||
mat!{match_repetition_30, r"((..)|(.))", r"aa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None}
|
||||
mat!{match_repetition_31, r"((..)|(.))((..)|(.))", r"aa", Some((0, 2)), Some((0, 1)), None, Some((0, 1)), Some((1, 2)), None, Some((1, 2))}
|
||||
mat!{match_repetition_32, r"((..)|(.))((..)|(.))((..)|(.))", r"aa", None}
|
||||
mat!{match_repetition_34, r"((..)|(.)){1}", r"aa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None}
|
||||
mat!{match_repetition_35, r"((..)|(.)){2}", r"aa", Some((0, 2)), Some((1, 2)), None, Some((1, 2))}
|
||||
mat!{match_repetition_36, r"((..)|(.)){3}", r"aa", None}
|
||||
mat!{match_repetition_38, r"((..)|(.))*", r"aa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None}
|
||||
mat!{match_repetition_40, r"((..)|(.))", r"aaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None}
|
||||
mat!{match_repetition_41, r"((..)|(.))((..)|(.))", r"aaa", Some((0, 3)), Some((0, 2)), Some((0, 2)), None, Some((2, 3)), None, Some((2, 3))}
|
||||
mat!{match_repetition_42, r"((..)|(.))((..)|(.))((..)|(.))", r"aaa", Some((0, 3)), Some((0, 1)), None, Some((0, 1)), Some((1, 2)), None, Some((1, 2)), Some((2, 3)), None, Some((2, 3))}
|
||||
mat!{match_repetition_44, r"((..)|(.)){1}", r"aaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None}
|
||||
mat!{match_repetition_46, r"((..)|(.)){2}", r"aaa", Some((0, 3)), Some((2, 3)), Some((0, 2)), Some((2, 3))}
|
||||
mat!{match_repetition_47, r"((..)|(.)){3}", r"aaa", Some((0, 3)), Some((2, 3)), None, Some((2, 3))}
|
||||
mat!{match_repetition_50, r"((..)|(.))*", r"aaa", Some((0, 3)), Some((2, 3)), Some((0, 2)), Some((2, 3))}
|
||||
mat!{match_repetition_52, r"((..)|(.))", r"aaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None}
|
||||
mat!{match_repetition_53, r"((..)|(.))((..)|(.))", r"aaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None}
|
||||
mat!{match_repetition_54, r"((..)|(.))((..)|(.))((..)|(.))", r"aaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 3)), None, Some((2, 3)), Some((3, 4)), None, Some((3, 4))}
|
||||
mat!{match_repetition_56, r"((..)|(.)){1}", r"aaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None}
|
||||
mat!{match_repetition_57, r"((..)|(.)){2}", r"aaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None}
|
||||
mat!{match_repetition_59, r"((..)|(.)){3}", r"aaaa", Some((0, 4)), Some((3, 4)), Some((0, 2)), Some((3, 4))}
|
||||
mat!{match_repetition_61, r"((..)|(.))*", r"aaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None}
|
||||
mat!{match_repetition_63, r"((..)|(.))", r"aaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None}
|
||||
mat!{match_repetition_64, r"((..)|(.))((..)|(.))", r"aaaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None}
|
||||
mat!{match_repetition_65, r"((..)|(.))((..)|(.))((..)|(.))", r"aaaaa", Some((0, 5)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None, Some((4, 5)), None, Some((4, 5))}
|
||||
mat!{match_repetition_67, r"((..)|(.)){1}", r"aaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None}
|
||||
mat!{match_repetition_68, r"((..)|(.)){2}", r"aaaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None}
|
||||
mat!{match_repetition_70, r"((..)|(.)){3}", r"aaaaa", Some((0, 5)), Some((4, 5)), Some((2, 4)), Some((4, 5))}
|
||||
mat!{match_repetition_73, r"((..)|(.))*", r"aaaaa", Some((0, 5)), Some((4, 5)), Some((2, 4)), Some((4, 5))}
|
||||
mat!{match_repetition_75, r"((..)|(.))", r"aaaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None}
|
||||
mat!{match_repetition_76, r"((..)|(.))((..)|(.))", r"aaaaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None}
|
||||
mat!{match_repetition_77, r"((..)|(.))((..)|(.))((..)|(.))", r"aaaaaa", Some((0, 6)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None, Some((4, 6)), Some((4, 6)), None}
|
||||
mat!{match_repetition_79, r"((..)|(.)){1}", r"aaaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None}
|
||||
mat!{match_repetition_80, r"((..)|(.)){2}", r"aaaaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None}
|
||||
mat!{match_repetition_81, r"((..)|(.)){3}", r"aaaaaa", Some((0, 6)), Some((4, 6)), Some((4, 6)), None}
|
||||
mat!{match_repetition_83, r"((..)|(.))*", r"aaaaaa", Some((0, 6)), Some((4, 6)), Some((4, 6)), None}
|
||||
mat!{match_repetition_90, r"X(.?){0,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))}
|
||||
mat!{match_repetition_91, r"X(.?){1,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))}
|
||||
mat!{match_repetition_92, r"X(.?){2,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))}
|
||||
mat!{match_repetition_93, r"X(.?){3,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))}
|
||||
mat!{match_repetition_94, r"X(.?){4,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))}
|
||||
mat!{match_repetition_95, r"X(.?){5,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))}
|
||||
mat!{match_repetition_96, r"X(.?){6,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))}
|
||||
mat!{match_repetition_97, r"X(.?){7,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))}
|
||||
mat!{match_repetition_98, r"X(.?){8,}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))}
|
||||
mat!{match_repetition_100, r"X(.?){0,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))}
|
||||
mat!{match_repetition_102, r"X(.?){1,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))}
|
||||
mat!{match_repetition_104, r"X(.?){2,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))}
|
||||
mat!{match_repetition_106, r"X(.?){3,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))}
|
||||
mat!{match_repetition_108, r"X(.?){4,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))}
|
||||
mat!{match_repetition_110, r"X(.?){5,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))}
|
||||
mat!{match_repetition_112, r"X(.?){6,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))}
|
||||
mat!{match_repetition_114, r"X(.?){7,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))}
|
||||
mat!{match_repetition_115, r"X(.?){8,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))}
|
||||
mat!{match_repetition_126, r"(a|ab|c|bcd){0,}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))}
|
||||
mat!{match_repetition_127, r"(a|ab|c|bcd){1,}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))}
|
||||
mat!{match_repetition_128, r"(a|ab|c|bcd){2,}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6))}
|
||||
mat!{match_repetition_129, r"(a|ab|c|bcd){3,}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6))}
|
||||
mat!{match_repetition_130, r"(a|ab|c|bcd){4,}(d*)", r"ababcd", None}
|
||||
mat!{match_repetition_131, r"(a|ab|c|bcd){0,10}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))}
|
||||
mat!{match_repetition_132, r"(a|ab|c|bcd){1,10}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))}
|
||||
mat!{match_repetition_133, r"(a|ab|c|bcd){2,10}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6))}
|
||||
mat!{match_repetition_134, r"(a|ab|c|bcd){3,10}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6))}
|
||||
mat!{match_repetition_135, r"(a|ab|c|bcd){4,10}(d*)", r"ababcd", None}
|
||||
mat!{match_repetition_136, r"(a|ab|c|bcd)*(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))}
|
||||
mat!{match_repetition_137, r"(a|ab|c|bcd)+(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))}
|
||||
mat!{match_repetition_143, r"(ab|a|c|bcd){0,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))}
|
||||
mat!{match_repetition_145, r"(ab|a|c|bcd){1,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))}
|
||||
mat!{match_repetition_147, r"(ab|a|c|bcd){2,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))}
|
||||
mat!{match_repetition_149, r"(ab|a|c|bcd){3,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))}
|
||||
mat!{match_repetition_150, r"(ab|a|c|bcd){4,}(d*)", r"ababcd", None}
|
||||
mat!{match_repetition_152, r"(ab|a|c|bcd){0,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))}
|
||||
mat!{match_repetition_154, r"(ab|a|c|bcd){1,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))}
|
||||
mat!{match_repetition_156, r"(ab|a|c|bcd){2,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))}
|
||||
mat!{match_repetition_158, r"(ab|a|c|bcd){3,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))}
|
||||
mat!{match_repetition_159, r"(ab|a|c|bcd){4,10}(d*)", r"ababcd", None}
|
||||
mat!{match_repetition_161, r"(ab|a|c|bcd)*(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))}
|
||||
mat!{match_repetition_163, r"(ab|a|c|bcd)+(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))}
|
||||
|
@ -1,26 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use regex::Regex;
|
||||
static RE: Regex = regex!(r"\d+");
|
||||
|
||||
#[test]
|
||||
fn static_splitn() {
|
||||
let text = "cauchy123plato456tyler789binx";
|
||||
let subs: Vec<&str> = RE.splitn(text, 2).collect();
|
||||
assert_eq!(subs, vec!("cauchy", "plato456tyler789binx"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn static_split() {
|
||||
let text = "cauchy123plato456tyler789binx";
|
||||
let subs: Vec<&str> = RE.split(text).collect();
|
||||
assert_eq!(subs, vec!("cauchy", "plato", "tyler", "binx"));
|
||||
}
|
@ -1,245 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-tidy-linelength
|
||||
// ignore-lexer-test FIXME #15679
|
||||
|
||||
use regex::{Regex, NoExpand};
|
||||
|
||||
#[test]
|
||||
fn splitn() {
|
||||
let re = regex!(r"\d+");
|
||||
let text = "cauchy123plato456tyler789binx";
|
||||
let subs: Vec<&str> = re.splitn(text, 2).collect();
|
||||
assert_eq!(subs, vec!("cauchy", "plato456tyler789binx"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split() {
|
||||
let re = regex!(r"\d+");
|
||||
let text = "cauchy123plato456tyler789binx";
|
||||
let subs: Vec<&str> = re.split(text).collect();
|
||||
assert_eq!(subs, vec!("cauchy", "plato", "tyler", "binx"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_regex_empty_match() {
|
||||
let re = regex!("");
|
||||
let ms = re.find_iter("").collect::<Vec<(uint, uint)>>();
|
||||
assert_eq!(ms, vec![(0, 0)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_regex_nonempty_match() {
|
||||
let re = regex!("");
|
||||
let ms = re.find_iter("abc").collect::<Vec<(uint, uint)>>();
|
||||
assert_eq!(ms, vec![(0, 0), (1, 1), (2, 2), (3, 3)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quoted_bracket_set() {
|
||||
let re = regex!(r"([\x{5b}\x{5d}])");
|
||||
let ms = re.find_iter("[]").collect::<Vec<(uint, uint)>>();
|
||||
assert_eq!(ms, vec![(0, 1), (1, 2)]);
|
||||
let re = regex!(r"([\[\]])");
|
||||
let ms = re.find_iter("[]").collect::<Vec<(uint, uint)>>();
|
||||
assert_eq!(ms, vec![(0, 1), (1, 2)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn first_range_starts_with_left_bracket() {
|
||||
let re = regex!(r"([[-z])");
|
||||
let ms = re.find_iter("[]").collect::<Vec<(uint, uint)>>();
|
||||
assert_eq!(ms, vec![(0, 1), (1, 2)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn range_ends_with_escape() {
|
||||
let re = regex!(r"([\[-\x{5d}])");
|
||||
let ms = re.find_iter("[]").collect::<Vec<(uint, uint)>>();
|
||||
assert_eq!(ms, vec![(0, 1), (1, 2)]);
|
||||
}
|
||||
|
||||
macro_rules! replace {
|
||||
($name:ident, $which:ident, $re:expr,
|
||||
$search:expr, $replace:expr, $result:expr) => (
|
||||
#[test]
|
||||
fn $name() {
|
||||
let re = regex!($re);
|
||||
assert_eq!(re.$which($search, $replace), String::from_str($result));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
replace!{rep_first, replace, r"\d", "age: 26", "Z", "age: Z6"}
|
||||
replace!{rep_plus, replace, r"\d+", "age: 26", "Z", "age: Z"}
|
||||
replace!{rep_all, replace_all, r"\d", "age: 26", "Z", "age: ZZ"}
|
||||
replace!{rep_groups, replace, r"(\S+)\s+(\S+)", "w1 w2", "$2 $1", "w2 w1"}
|
||||
replace!{rep_double_dollar, replace,
|
||||
r"(\S+)\s+(\S+)", "w1 w2", "$2 $$1", "w2 $1"}
|
||||
replace!{rep_no_expand, replace,
|
||||
r"(\S+)\s+(\S+)", "w1 w2", NoExpand("$2 $1"), "$2 $1"}
|
||||
replace!{rep_named, replace_all,
|
||||
r"(?P<first>\S+)\s+(?P<last>\S+)(?P<space>\s*)",
|
||||
"w1 w2 w3 w4", "$last $first$space", "w2 w1 w4 w3"}
|
||||
replace!{rep_trim, replace_all, "^[ \t]+|[ \t]+$", " \t trim me\t \t",
|
||||
"", "trim me"}
|
||||
|
||||
macro_rules! noparse {
|
||||
($name:ident, $re:expr) => (
|
||||
#[test]
|
||||
fn $name() {
|
||||
let re = $re;
|
||||
match Regex::new(re) {
|
||||
Err(_) => {},
|
||||
Ok(_) => panic!("Regex '{}' should cause a parse error.", re),
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
noparse!{fail_double_repeat, "a**"}
|
||||
noparse!{fail_no_repeat_arg, "*"}
|
||||
noparse!{fail_no_repeat_arg_begin, "^*"}
|
||||
noparse!{fail_incomplete_escape, "\\"}
|
||||
noparse!{fail_class_incomplete, "[A-"}
|
||||
noparse!{fail_class_not_closed, "[A"}
|
||||
noparse!{fail_class_no_begin, r"[\A]"}
|
||||
noparse!{fail_class_no_end, r"[\z]"}
|
||||
noparse!{fail_class_no_boundary, r"[\b]"}
|
||||
noparse!{fail_open_paren, "("}
|
||||
noparse!{fail_close_paren, ")"}
|
||||
noparse!{fail_invalid_range, "[a-Z]"}
|
||||
noparse!{fail_empty_capture_name, "(?P<>a)"}
|
||||
noparse!{fail_empty_capture_exp, "(?P<name>)"}
|
||||
noparse!{fail_bad_capture_name, "(?P<na-me>)"}
|
||||
noparse!{fail_bad_flag, "(?a)a"}
|
||||
noparse!{fail_empty_alt_before, "|a"}
|
||||
noparse!{fail_empty_alt_after, "a|"}
|
||||
noparse!{fail_counted_big_exact, "a{1001}"}
|
||||
noparse!{fail_counted_big_min, "a{1001,}"}
|
||||
noparse!{fail_counted_no_close, "a{1001"}
|
||||
noparse!{fail_unfinished_cap, "(?"}
|
||||
noparse!{fail_unfinished_escape, "\\"}
|
||||
noparse!{fail_octal_digit, r"\8"}
|
||||
noparse!{fail_hex_digit, r"\xG0"}
|
||||
noparse!{fail_hex_short, r"\xF"}
|
||||
noparse!{fail_hex_long_digits, r"\x{fffg}"}
|
||||
noparse!{fail_flag_bad, "(?a)"}
|
||||
noparse!{fail_flag_empty, "(?)"}
|
||||
noparse!{fail_double_neg, "(?-i-i)"}
|
||||
noparse!{fail_neg_empty, "(?i-)"}
|
||||
noparse!{fail_empty_group, "()"}
|
||||
noparse!{fail_dupe_named, "(?P<a>.)(?P<a>.)"}
|
||||
noparse!{fail_range_end_no_class, "[a-[:lower:]]"}
|
||||
noparse!{fail_range_end_no_begin, r"[a-\A]"}
|
||||
noparse!{fail_range_end_no_end, r"[a-\z]"}
|
||||
noparse!{fail_range_end_no_boundary, r"[a-\b]"}
|
||||
noparse!{fail_repeat_no_expr, r"-|+"}
|
||||
|
||||
macro_rules! mat {
|
||||
($name:ident, $re:expr, $text:expr, $($loc:tt)+) => (
|
||||
#[test]
|
||||
fn $name() {
|
||||
let text = $text;
|
||||
let expected: Vec<Option<(uint, uint)>> = vec!($($loc)+);
|
||||
let r = regex!($re);
|
||||
let got = match r.captures(text) {
|
||||
Some(c) => c.iter_pos().collect::<Vec<Option<(uint, uint)>>>(),
|
||||
None => vec!(None),
|
||||
};
|
||||
// The test set sometimes leave out capture groups, so truncate
|
||||
// actual capture groups to match test set.
|
||||
let mut sgot = got.as_slice();
|
||||
if sgot.len() > expected.len() {
|
||||
sgot = &sgot[..expected.len()]
|
||||
}
|
||||
if expected != sgot {
|
||||
panic!("For RE '{}' against '{}', expected '{:?}' but got '{:?}'",
|
||||
$re, text, expected, sgot);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Some crazy expressions from regular-expressions.info.
|
||||
mat!{match_ranges,
|
||||
r"\b(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b",
|
||||
"num: 255", Some((5, 8))}
|
||||
mat!{match_ranges_not,
|
||||
r"\b(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b",
|
||||
"num: 256", None}
|
||||
mat!{match_float1, r"[-+]?[0-9]*\.?[0-9]+", "0.1", Some((0, 3))}
|
||||
mat!{match_float2, r"[-+]?[0-9]*\.?[0-9]+", "0.1.2", Some((0, 3))}
|
||||
mat!{match_float3, r"[-+]?[0-9]*\.?[0-9]+", "a1.2", Some((1, 4))}
|
||||
mat!{match_float4, r"^[-+]?[0-9]*\.?[0-9]+$", "1.a", None}
|
||||
mat!{match_email, r"(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b",
|
||||
"mine is jam.slam@gmail.com ", Some((8, 26))}
|
||||
mat!{match_email_not, r"(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b",
|
||||
"mine is jam.slam@gmail ", None}
|
||||
mat!{match_email_big, r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
|
||||
"mine is jam.slam@gmail.com ", Some((8, 26))}
|
||||
mat!{match_date1,
|
||||
r"^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$",
|
||||
"1900-01-01", Some((0, 10))}
|
||||
mat!{match_date2,
|
||||
r"^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$",
|
||||
"1900-00-01", None}
|
||||
mat!{match_date3,
|
||||
r"^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$",
|
||||
"1900-13-01", None}
|
||||
|
||||
// Exercise the flags.
|
||||
mat!{match_flag_case, "(?i)abc", "ABC", Some((0, 3))}
|
||||
mat!{match_flag_weird_case, "(?i)a(?-i)bc", "Abc", Some((0, 3))}
|
||||
mat!{match_flag_weird_case_not, "(?i)a(?-i)bc", "ABC", None}
|
||||
mat!{match_flag_case_dotnl, "(?is)a.", "A\n", Some((0, 2))}
|
||||
mat!{match_flag_case_dotnl_toggle, "(?is)a.(?-is)a.", "A\nab", Some((0, 4))}
|
||||
mat!{match_flag_case_dotnl_toggle_not, "(?is)a.(?-is)a.", "A\na\n", None}
|
||||
mat!{match_flag_case_dotnl_toggle_ok, "(?is)a.(?-is:a.)?", "A\na\n", Some((0, 2))}
|
||||
mat!{match_flag_multi, "(?m)(?:^\\d+$\n?)+", "123\n456\n789", Some((0, 11))}
|
||||
mat!{match_flag_ungreedy, "(?U)a+", "aa", Some((0, 1))}
|
||||
mat!{match_flag_ungreedy_greedy, "(?U)a+?", "aa", Some((0, 2))}
|
||||
mat!{match_flag_ungreedy_noop, "(?U)(?-U)a+", "aa", Some((0, 2))}
|
||||
|
||||
// Some Unicode tests.
|
||||
// A couple of these are commented out because something in the guts of macro expansion is creating
|
||||
// invalid byte strings.
|
||||
//mat!{uni_literal, r"Ⅰ", "Ⅰ", Some((0, 3))}
|
||||
mat!{uni_one, r"\pN", "Ⅰ", Some((0, 3))}
|
||||
mat!{uni_mixed, r"\pN+", "Ⅰ1Ⅱ2", Some((0, 8))}
|
||||
mat!{uni_not, r"\PN+", "abⅠ", Some((0, 2))}
|
||||
mat!{uni_not_class, r"[\PN]+", "abⅠ", Some((0, 2))}
|
||||
mat!{uni_not_class_neg, r"[^\PN]+", "abⅠ", Some((2, 5))}
|
||||
mat!{uni_case, r"(?i)Δ", "δ", Some((0, 2))}
|
||||
//mat!{uni_case_not, r"Δ", "δ", None}
|
||||
mat!{uni_case_upper, r"\p{Lu}+", "ΛΘΓΔα", Some((0, 8))}
|
||||
mat!{uni_case_upper_nocase_flag, r"(?i)\p{Lu}+", "ΛΘΓΔα", Some((0, 10))}
|
||||
mat!{uni_case_upper_nocase, r"\p{L}+", "ΛΘΓΔα", Some((0, 10))}
|
||||
mat!{uni_case_lower, r"\p{Ll}+", "ΛΘΓΔα", Some((8, 10))}
|
||||
|
||||
// Test the Unicode friendliness of Perl character classes.
|
||||
mat!{uni_perl_w, r"\w+", "dδd", Some((0, 4))}
|
||||
mat!{uni_perl_w_not, r"\w+", "⥡", None}
|
||||
mat!{uni_perl_w_neg, r"\W+", "⥡", Some((0, 3))}
|
||||
mat!{uni_perl_d, r"\d+", "1२३9", Some((0, 8))}
|
||||
mat!{uni_perl_d_not, r"\d+", "Ⅱ", None}
|
||||
mat!{uni_perl_d_neg, r"\D+", "Ⅱ", Some((0, 3))}
|
||||
mat!{uni_perl_s, r"\s+", " ", Some((0, 3))}
|
||||
mat!{uni_perl_s_not, r"\s+", "☃", None}
|
||||
mat!{uni_perl_s_neg, r"\S+", "☃", Some((0, 3))}
|
||||
|
||||
// And do the same for word boundaries.
|
||||
mat!{uni_boundary_none, r"\d\b", "6δ", None}
|
||||
mat!{uni_boundary_ogham, r"\d\b", "6 ", Some((0, 1))}
|
||||
|
||||
// A whole mess of tests from Glenn Fowler's regex test suite.
|
||||
// Generated by the 'src/etc/regex-match-tests' program.
|
||||
mod matches;
|
19
src/libregex/testdata/LICENSE
vendored
19
src/libregex/testdata/LICENSE
vendored
@ -1,19 +0,0 @@
|
||||
The following license covers testregex.c and all associated test data.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software
|
||||
without restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, and/or sell copies of the
|
||||
Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following disclaimer:
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
17
src/libregex/testdata/README
vendored
17
src/libregex/testdata/README
vendored
@ -1,17 +0,0 @@
|
||||
Test data was taken from the Go distribution, which was in turn taken from the
|
||||
testregex test suite:
|
||||
|
||||
http://www2.research.att.com/~astopen/testregex/testregex.html
|
||||
|
||||
The LICENSE in this directory corresponds to the LICENSE that the data was
|
||||
released under.
|
||||
|
||||
The tests themselves were modified for RE2/Go. A couple were modified further
|
||||
by me (Andrew Gallant) (only in repetition.dat) so that RE2/Go would pass them.
|
||||
(Yes, it seems like RE2/Go includes failing test cases.) This may or may not
|
||||
have been a bad idea, but I think being consistent with an established Regex
|
||||
library is worth something.
|
||||
|
||||
Note that these files are read by 'src/etc/regexp-match-tests' and turned into
|
||||
Rust tests found in 'src/libregexp/tests/matches.rs'.
|
||||
|
221
src/libregex/testdata/basic.dat
vendored
221
src/libregex/testdata/basic.dat
vendored
@ -1,221 +0,0 @@
|
||||
NOTE all standard compliant implementations should pass these : 2002-05-31
|
||||
|
||||
BE abracadabra$ abracadabracadabra (7,18)
|
||||
BE a...b abababbb (2,7)
|
||||
BE XXXXXX ..XXXXXX (2,8)
|
||||
E \) () (1,2)
|
||||
BE a] a]a (0,2)
|
||||
B } } (0,1)
|
||||
E \} } (0,1)
|
||||
BE \] ] (0,1)
|
||||
B ] ] (0,1)
|
||||
E ] ] (0,1)
|
||||
B { { (0,1)
|
||||
B } } (0,1)
|
||||
BE ^a ax (0,1)
|
||||
BE \^a a^a (1,3)
|
||||
BE a\^ a^ (0,2)
|
||||
BE a$ aa (1,2)
|
||||
BE a\$ a$ (0,2)
|
||||
BE ^$ NULL (0,0)
|
||||
E $^ NULL (0,0)
|
||||
E a($) aa (1,2)(2,2)
|
||||
E a*(^a) aa (0,1)(0,1)
|
||||
E (..)*(...)* a (0,0)
|
||||
E (..)*(...)* abcd (0,4)(2,4)
|
||||
E (ab|a)(bc|c) abc (0,3)(0,2)(2,3)
|
||||
E (ab)c|abc abc (0,3)(0,2)
|
||||
E a{0}b ab (1,2)
|
||||
E (a*)(b?)(b+)b{3} aaabbbbbbb (0,10)(0,3)(3,4)(4,7)
|
||||
E (a*)(b{0,1})(b{1,})b{3} aaabbbbbbb (0,10)(0,3)(3,4)(4,7)
|
||||
E a{9876543210} NULL BADBR
|
||||
E ((a|a)|a) a (0,1)(0,1)(0,1)
|
||||
E (a*)(a|aa) aaaa (0,4)(0,3)(3,4)
|
||||
E a*(a.|aa) aaaa (0,4)(2,4)
|
||||
E a(b)|c(d)|a(e)f aef (0,3)(?,?)(?,?)(1,2)
|
||||
E (a|b)?.* b (0,1)(0,1)
|
||||
E (a|b)c|a(b|c) ac (0,2)(0,1)
|
||||
E (a|b)c|a(b|c) ab (0,2)(?,?)(1,2)
|
||||
E (a|b)*c|(a|ab)*c abc (0,3)(1,2)
|
||||
E (a|b)*c|(a|ab)*c xc (1,2)
|
||||
E (.a|.b).*|.*(.a|.b) xa (0,2)(0,2)
|
||||
E a?(ab|ba)ab abab (0,4)(0,2)
|
||||
E a?(ac{0}b|ba)ab abab (0,4)(0,2)
|
||||
E ab|abab abbabab (0,2)
|
||||
E aba|bab|bba baaabbbaba (5,8)
|
||||
E aba|bab baaabbbaba (6,9)
|
||||
E (aa|aaa)*|(a|aaaaa) aa (0,2)(0,2)
|
||||
E (a.|.a.)*|(a|.a...) aa (0,2)(0,2)
|
||||
E ab|a xabc (1,3)
|
||||
E ab|a xxabc (2,4)
|
||||
Ei (Ab|cD)* aBcD (0,4)(2,4)
|
||||
BE [^-] --a (2,3)
|
||||
BE [a-]* --a (0,3)
|
||||
BE [a-m-]* --amoma-- (0,4)
|
||||
E :::1:::0:|:::1:1:0: :::0:::1:::1:::0: (8,17)
|
||||
E :::1:::0:|:::1:1:1: :::0:::1:::1:::0: (8,17)
|
||||
{E [[:upper:]] A (0,1) [[<element>]] not supported
|
||||
E [[:lower:]]+ `az{ (1,3)
|
||||
E [[:upper:]]+ @AZ[ (1,3)
|
||||
# No collation in Go
|
||||
#BE [[-]] [[-]] (2,4)
|
||||
#BE [[.NIL.]] NULL ECOLLATE
|
||||
#BE [[=aleph=]] NULL ECOLLATE
|
||||
}
|
||||
BE$ \n \n (0,1)
|
||||
BEn$ \n \n (0,1)
|
||||
BE$ [^a] \n (0,1)
|
||||
BE$ \na \na (0,2)
|
||||
E (a)(b)(c) abc (0,3)(0,1)(1,2)(2,3)
|
||||
BE xxx xxx (0,3)
|
||||
E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) feb 6, (0,6)
|
||||
E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) 2/7 (0,3)
|
||||
E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) feb 1,Feb 6 (5,11)
|
||||
E3 ((((((((((((((((((((((((((((((x)))))))))))))))))))))))))))))) x (0,1)(0,1)(0,1)
|
||||
E3 ((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))* xx (0,2)(1,2)(1,2)
|
||||
E a?(ab|ba)* ababababababababababababababababababababababababababababababababababababababababa (0,81)(79,81)
|
||||
E abaa|abbaa|abbbaa|abbbbaa ababbabbbabbbabbbbabbbbaa (18,25)
|
||||
E abaa|abbaa|abbbaa|abbbbaa ababbabbbabbbabbbbabaa (18,22)
|
||||
E aaac|aabc|abac|abbc|baac|babc|bbac|bbbc baaabbbabac (7,11)
|
||||
BE$ .* \x01\x7f (0,2)
|
||||
E aaaa|bbbb|cccc|ddddd|eeeeee|fffffff|gggg|hhhh|iiiii|jjjjj|kkkkk|llll XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa (53,57)
|
||||
L aaaa\nbbbb\ncccc\nddddd\neeeeee\nfffffff\ngggg\nhhhh\niiiii\njjjjj\nkkkkk\nllll XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa NOMATCH
|
||||
E a*a*a*a*a*b aaaaaaaaab (0,10)
|
||||
BE ^ NULL (0,0)
|
||||
BE $ NULL (0,0)
|
||||
BE ^$ NULL (0,0)
|
||||
BE ^a$ a (0,1)
|
||||
BE abc abc (0,3)
|
||||
BE abc xabcy (1,4)
|
||||
BE abc ababc (2,5)
|
||||
BE ab*c abc (0,3)
|
||||
BE ab*bc abc (0,3)
|
||||
BE ab*bc abbc (0,4)
|
||||
BE ab*bc abbbbc (0,6)
|
||||
E ab+bc abbc (0,4)
|
||||
E ab+bc abbbbc (0,6)
|
||||
E ab?bc abbc (0,4)
|
||||
E ab?bc abc (0,3)
|
||||
E ab?c abc (0,3)
|
||||
BE ^abc$ abc (0,3)
|
||||
BE ^abc abcc (0,3)
|
||||
BE abc$ aabc (1,4)
|
||||
BE ^ abc (0,0)
|
||||
BE $ abc (3,3)
|
||||
BE a.c abc (0,3)
|
||||
BE a.c axc (0,3)
|
||||
BE a.*c axyzc (0,5)
|
||||
BE a[bc]d abd (0,3)
|
||||
BE a[b-d]e ace (0,3)
|
||||
BE a[b-d] aac (1,3)
|
||||
BE a[-b] a- (0,2)
|
||||
BE a[b-] a- (0,2)
|
||||
BE a] a] (0,2)
|
||||
BE a[]]b a]b (0,3)
|
||||
BE a[^bc]d aed (0,3)
|
||||
BE a[^-b]c adc (0,3)
|
||||
BE a[^]b]c adc (0,3)
|
||||
E ab|cd abc (0,2)
|
||||
E ab|cd abcd (0,2)
|
||||
E a\(b a(b (0,3)
|
||||
E a\(*b ab (0,2)
|
||||
E a\(*b a((b (0,4)
|
||||
E ((a)) abc (0,1)(0,1)(0,1)
|
||||
E (a)b(c) abc (0,3)(0,1)(2,3)
|
||||
E a+b+c aabbabc (4,7)
|
||||
E a* aaa (0,3)
|
||||
#E (a*)* - (0,0)(0,0)
|
||||
E (a*)* - (0,0)(?,?) RE2/Go
|
||||
E (a*)+ - (0,0)(0,0)
|
||||
#E (a*|b)* - (0,0)(0,0)
|
||||
E (a*|b)* - (0,0)(?,?) RE2/Go
|
||||
E (a+|b)* ab (0,2)(1,2)
|
||||
E (a+|b)+ ab (0,2)(1,2)
|
||||
E (a+|b)? ab (0,1)(0,1)
|
||||
BE [^ab]* cde (0,3)
|
||||
#E (^)* - (0,0)(0,0)
|
||||
E (^)* - (0,0)(?,?) RE2/Go
|
||||
BE a* NULL (0,0)
|
||||
E ([abc])*d abbbcd (0,6)(4,5)
|
||||
E ([abc])*bcd abcd (0,4)(0,1)
|
||||
E a|b|c|d|e e (0,1)
|
||||
E (a|b|c|d|e)f ef (0,2)(0,1)
|
||||
#E ((a*|b))* - (0,0)(0,0)(0,0)
|
||||
E ((a*|b))* - (0,0)(?,?)(?,?) RE2/Go
|
||||
BE abcd*efg abcdefg (0,7)
|
||||
BE ab* xabyabbbz (1,3)
|
||||
BE ab* xayabbbz (1,2)
|
||||
E (ab|cd)e abcde (2,5)(2,4)
|
||||
BE [abhgefdc]ij hij (0,3)
|
||||
E (a|b)c*d abcd (1,4)(1,2)
|
||||
E (ab|ab*)bc abc (0,3)(0,1)
|
||||
E a([bc]*)c* abc (0,3)(1,3)
|
||||
E a([bc]*)(c*d) abcd (0,4)(1,3)(3,4)
|
||||
E a([bc]+)(c*d) abcd (0,4)(1,3)(3,4)
|
||||
E a([bc]*)(c+d) abcd (0,4)(1,2)(2,4)
|
||||
E a[bcd]*dcdcde adcdcde (0,7)
|
||||
E (ab|a)b*c abc (0,3)(0,2)
|
||||
E ((a)(b)c)(d) abcd (0,4)(0,3)(0,1)(1,2)(3,4)
|
||||
BE [A-Za-z_][A-Za-z0-9_]* alpha (0,5)
|
||||
E ^a(bc+|b[eh])g|.h$ abh (1,3)
|
||||
E (bc+d$|ef*g.|h?i(j|k)) effgz (0,5)(0,5)
|
||||
E (bc+d$|ef*g.|h?i(j|k)) ij (0,2)(0,2)(1,2)
|
||||
E (bc+d$|ef*g.|h?i(j|k)) reffgz (1,6)(1,6)
|
||||
E (((((((((a))))))))) a (0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)
|
||||
BE multiple words multiple words yeah (0,14)
|
||||
E (.*)c(.*) abcde (0,5)(0,2)(3,5)
|
||||
BE abcd abcd (0,4)
|
||||
E a(bc)d abcd (0,4)(1,3)
|
||||
E a[-]?c ac (0,3)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Qaddafi (0,15)(?,?)(10,12)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mo'ammar Gadhafi (0,16)(?,?)(11,13)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Kaddafi (0,15)(?,?)(10,12)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Qadhafi (0,15)(?,?)(10,12)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Gadafi (0,14)(?,?)(10,11)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mu'ammar Qadafi (0,15)(?,?)(11,12)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moamar Gaddafi (0,14)(?,?)(9,11)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mu'ammar Qadhdhafi (0,18)(?,?)(13,15)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Khaddafi (0,16)(?,?)(11,13)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghaddafy (0,16)(?,?)(11,13)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghadafi (0,15)(?,?)(11,12)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghaddafi (0,16)(?,?)(11,13)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muamar Kaddafi (0,14)(?,?)(9,11)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Quathafi (0,16)(?,?)(11,13)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Gheddafi (0,16)(?,?)(11,13)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moammar Khadafy (0,15)(?,?)(11,12)
|
||||
E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moammar Qudhafi (0,15)(?,?)(10,12)
|
||||
E a+(b|c)*d+ aabcdd (0,6)(3,4)
|
||||
E ^.+$ vivi (0,4)
|
||||
E ^(.+)$ vivi (0,4)(0,4)
|
||||
E ^([^!.]+).att.com!(.+)$ gryphon.att.com!eby (0,19)(0,7)(16,19)
|
||||
E ^([^!]+!)?([^!]+)$ bas (0,3)(?,?)(0,3)
|
||||
E ^([^!]+!)?([^!]+)$ bar!bas (0,7)(0,4)(4,7)
|
||||
E ^([^!]+!)?([^!]+)$ foo!bas (0,7)(0,4)(4,7)
|
||||
E ^.+!([^!]+!)([^!]+)$ foo!bar!bas (0,11)(4,8)(8,11)
|
||||
E ((foo)|(bar))!bas bar!bas (0,7)(0,3)(?,?)(0,3)
|
||||
E ((foo)|(bar))!bas foo!bar!bas (4,11)(4,7)(?,?)(4,7)
|
||||
E ((foo)|(bar))!bas foo!bas (0,7)(0,3)(0,3)
|
||||
E ((foo)|bar)!bas bar!bas (0,7)(0,3)
|
||||
E ((foo)|bar)!bas foo!bar!bas (4,11)(4,7)
|
||||
E ((foo)|bar)!bas foo!bas (0,7)(0,3)(0,3)
|
||||
E (foo|(bar))!bas bar!bas (0,7)(0,3)(0,3)
|
||||
E (foo|(bar))!bas foo!bar!bas (4,11)(4,7)(4,7)
|
||||
E (foo|(bar))!bas foo!bas (0,7)(0,3)
|
||||
E (foo|bar)!bas bar!bas (0,7)(0,3)
|
||||
E (foo|bar)!bas foo!bar!bas (4,11)(4,7)
|
||||
E (foo|bar)!bas foo!bas (0,7)(0,3)
|
||||
E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bar!bas (0,11)(0,11)(?,?)(?,?)(4,8)(8,11)
|
||||
E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ bas (0,3)(?,?)(0,3)
|
||||
E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ bar!bas (0,7)(0,4)(4,7)
|
||||
E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ foo!bar!bas (0,11)(?,?)(?,?)(4,8)(8,11)
|
||||
E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ foo!bas (0,7)(0,4)(4,7)
|
||||
E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ bas (0,3)(0,3)(?,?)(0,3)
|
||||
E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ bar!bas (0,7)(0,7)(0,4)(4,7)
|
||||
E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bar!bas (0,11)(0,11)(?,?)(?,?)(4,8)(8,11)
|
||||
E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bas (0,7)(0,7)(0,4)(4,7)
|
||||
E .*(/XXX).* /XXX (0,4)(0,4)
|
||||
E .*(\\XXX).* \XXX (0,4)(0,4)
|
||||
E \\XXX \XXX (0,4)
|
||||
E .*(/000).* /000 (0,4)(0,4)
|
||||
E .*(\\000).* \000 (0,4)(0,4)
|
||||
E \\000 \000 (0,4)
|
79
src/libregex/testdata/nullsubexpr.dat
vendored
79
src/libregex/testdata/nullsubexpr.dat
vendored
@ -1,79 +0,0 @@
|
||||
NOTE null subexpression matches : 2002-06-06
|
||||
|
||||
E (a*)* a (0,1)(0,1)
|
||||
#E SAME x (0,0)(0,0)
|
||||
E SAME x (0,0)(?,?) RE2/Go
|
||||
E SAME aaaaaa (0,6)(0,6)
|
||||
E SAME aaaaaax (0,6)(0,6)
|
||||
E (a*)+ a (0,1)(0,1)
|
||||
E SAME x (0,0)(0,0)
|
||||
E SAME aaaaaa (0,6)(0,6)
|
||||
E SAME aaaaaax (0,6)(0,6)
|
||||
E (a+)* a (0,1)(0,1)
|
||||
E SAME x (0,0)
|
||||
E SAME aaaaaa (0,6)(0,6)
|
||||
E SAME aaaaaax (0,6)(0,6)
|
||||
E (a+)+ a (0,1)(0,1)
|
||||
E SAME x NOMATCH
|
||||
E SAME aaaaaa (0,6)(0,6)
|
||||
E SAME aaaaaax (0,6)(0,6)
|
||||
|
||||
E ([a]*)* a (0,1)(0,1)
|
||||
#E SAME x (0,0)(0,0)
|
||||
E SAME x (0,0)(?,?) RE2/Go
|
||||
E SAME aaaaaa (0,6)(0,6)
|
||||
E SAME aaaaaax (0,6)(0,6)
|
||||
E ([a]*)+ a (0,1)(0,1)
|
||||
E SAME x (0,0)(0,0)
|
||||
E SAME aaaaaa (0,6)(0,6)
|
||||
E SAME aaaaaax (0,6)(0,6)
|
||||
E ([^b]*)* a (0,1)(0,1)
|
||||
#E SAME b (0,0)(0,0)
|
||||
E SAME b (0,0)(?,?) RE2/Go
|
||||
E SAME aaaaaa (0,6)(0,6)
|
||||
E SAME aaaaaab (0,6)(0,6)
|
||||
E ([ab]*)* a (0,1)(0,1)
|
||||
E SAME aaaaaa (0,6)(0,6)
|
||||
E SAME ababab (0,6)(0,6)
|
||||
E SAME bababa (0,6)(0,6)
|
||||
E SAME b (0,1)(0,1)
|
||||
E SAME bbbbbb (0,6)(0,6)
|
||||
E SAME aaaabcde (0,5)(0,5)
|
||||
E ([^a]*)* b (0,1)(0,1)
|
||||
E SAME bbbbbb (0,6)(0,6)
|
||||
#E SAME aaaaaa (0,0)(0,0)
|
||||
E SAME aaaaaa (0,0)(?,?) RE2/Go
|
||||
E ([^ab]*)* ccccxx (0,6)(0,6)
|
||||
#E SAME ababab (0,0)(0,0)
|
||||
E SAME ababab (0,0)(?,?) RE2/Go
|
||||
|
||||
E ((z)+|a)* zabcde (0,2)(1,2)
|
||||
|
||||
#{E a+? aaaaaa (0,1) no *? +? mimimal match ops
|
||||
#E (a) aaa (0,1)(0,1)
|
||||
#E (a*?) aaa (0,0)(0,0)
|
||||
#E (a)*? aaa (0,0)
|
||||
#E (a*?)*? aaa (0,0)
|
||||
#}
|
||||
|
||||
B \(a*\)*\(x\) x (0,1)(0,0)(0,1)
|
||||
B \(a*\)*\(x\) ax (0,2)(0,1)(1,2)
|
||||
B \(a*\)*\(x\) axa (0,2)(0,1)(1,2)
|
||||
B \(a*\)*\(x\)\(\1\) x (0,1)(0,0)(0,1)(1,1)
|
||||
B \(a*\)*\(x\)\(\1\) ax (0,2)(1,1)(1,2)(2,2)
|
||||
B \(a*\)*\(x\)\(\1\) axa (0,3)(0,1)(1,2)(2,3)
|
||||
B \(a*\)*\(x\)\(\1\)\(x\) axax (0,4)(0,1)(1,2)(2,3)(3,4)
|
||||
B \(a*\)*\(x\)\(\1\)\(x\) axxa (0,3)(1,1)(1,2)(2,2)(2,3)
|
||||
|
||||
#E (a*)*(x) x (0,1)(0,0)(0,1)
|
||||
E (a*)*(x) x (0,1)(?,?)(0,1) RE2/Go
|
||||
E (a*)*(x) ax (0,2)(0,1)(1,2)
|
||||
E (a*)*(x) axa (0,2)(0,1)(1,2)
|
||||
|
||||
E (a*)+(x) x (0,1)(0,0)(0,1)
|
||||
E (a*)+(x) ax (0,2)(0,1)(1,2)
|
||||
E (a*)+(x) axa (0,2)(0,1)(1,2)
|
||||
|
||||
E (a*){2}(x) x (0,1)(0,0)(0,1)
|
||||
E (a*){2}(x) ax (0,2)(1,1)(1,2)
|
||||
E (a*){2}(x) axa (0,2)(1,1)(1,2)
|
163
src/libregex/testdata/repetition.dat
vendored
163
src/libregex/testdata/repetition.dat
vendored
@ -1,163 +0,0 @@
|
||||
NOTE implicit vs. explicit repetitions : 2009-02-02
|
||||
|
||||
# Glenn Fowler <gsf@research.att.com>
|
||||
# conforming matches (column 4) must match one of the following BREs
|
||||
# NOMATCH
|
||||
# (0,.)\((\(.\),\(.\))(?,?)(\2,\3)\)*
|
||||
# (0,.)\((\(.\),\(.\))(\2,\3)(?,?)\)*
|
||||
# i.e., each 3-tuple has two identical elements and one (?,?)
|
||||
|
||||
E ((..)|(.)) NULL NOMATCH
|
||||
E ((..)|(.))((..)|(.)) NULL NOMATCH
|
||||
E ((..)|(.))((..)|(.))((..)|(.)) NULL NOMATCH
|
||||
|
||||
E ((..)|(.)){1} NULL NOMATCH
|
||||
E ((..)|(.)){2} NULL NOMATCH
|
||||
E ((..)|(.)){3} NULL NOMATCH
|
||||
|
||||
E ((..)|(.))* NULL (0,0)
|
||||
|
||||
E ((..)|(.)) a (0,1)(0,1)(?,?)(0,1)
|
||||
E ((..)|(.))((..)|(.)) a NOMATCH
|
||||
E ((..)|(.))((..)|(.))((..)|(.)) a NOMATCH
|
||||
|
||||
E ((..)|(.)){1} a (0,1)(0,1)(?,?)(0,1)
|
||||
E ((..)|(.)){2} a NOMATCH
|
||||
E ((..)|(.)){3} a NOMATCH
|
||||
|
||||
E ((..)|(.))* a (0,1)(0,1)(?,?)(0,1)
|
||||
|
||||
E ((..)|(.)) aa (0,2)(0,2)(0,2)(?,?)
|
||||
E ((..)|(.))((..)|(.)) aa (0,2)(0,1)(?,?)(0,1)(1,2)(?,?)(1,2)
|
||||
E ((..)|(.))((..)|(.))((..)|(.)) aa NOMATCH
|
||||
|
||||
E ((..)|(.)){1} aa (0,2)(0,2)(0,2)(?,?)
|
||||
E ((..)|(.)){2} aa (0,2)(1,2)(?,?)(1,2)
|
||||
E ((..)|(.)){3} aa NOMATCH
|
||||
|
||||
E ((..)|(.))* aa (0,2)(0,2)(0,2)(?,?)
|
||||
|
||||
E ((..)|(.)) aaa (0,2)(0,2)(0,2)(?,?)
|
||||
E ((..)|(.))((..)|(.)) aaa (0,3)(0,2)(0,2)(?,?)(2,3)(?,?)(2,3)
|
||||
E ((..)|(.))((..)|(.))((..)|(.)) aaa (0,3)(0,1)(?,?)(0,1)(1,2)(?,?)(1,2)(2,3)(?,?)(2,3)
|
||||
|
||||
E ((..)|(.)){1} aaa (0,2)(0,2)(0,2)(?,?)
|
||||
#E ((..)|(.)){2} aaa (0,3)(2,3)(?,?)(2,3)
|
||||
E ((..)|(.)){2} aaa (0,3)(2,3)(0,2)(2,3) RE2/Go
|
||||
E ((..)|(.)){3} aaa (0,3)(2,3)(?,?)(2,3)
|
||||
|
||||
#E ((..)|(.))* aaa (0,3)(2,3)(?,?)(2,3)
|
||||
E ((..)|(.))* aaa (0,3)(2,3)(0,2)(2,3) RE2/Go
|
||||
|
||||
E ((..)|(.)) aaaa (0,2)(0,2)(0,2)(?,?)
|
||||
E ((..)|(.))((..)|(.)) aaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
|
||||
E ((..)|(.))((..)|(.))((..)|(.)) aaaa (0,4)(0,2)(0,2)(?,?)(2,3)(?,?)(2,3)(3,4)(?,?)(3,4)
|
||||
|
||||
E ((..)|(.)){1} aaaa (0,2)(0,2)(0,2)(?,?)
|
||||
E ((..)|(.)){2} aaaa (0,4)(2,4)(2,4)(?,?)
|
||||
#E ((..)|(.)){3} aaaa (0,4)(3,4)(?,?)(3,4)
|
||||
E ((..)|(.)){3} aaaa (0,4)(3,4)(0,2)(3,4) RE2/Go
|
||||
|
||||
E ((..)|(.))* aaaa (0,4)(2,4)(2,4)(?,?)
|
||||
|
||||
E ((..)|(.)) aaaaa (0,2)(0,2)(0,2)(?,?)
|
||||
E ((..)|(.))((..)|(.)) aaaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
|
||||
E ((..)|(.))((..)|(.))((..)|(.)) aaaaa (0,5)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)(4,5)(?,?)(4,5)
|
||||
|
||||
E ((..)|(.)){1} aaaaa (0,2)(0,2)(0,2)(?,?)
|
||||
E ((..)|(.)){2} aaaaa (0,4)(2,4)(2,4)(?,?)
|
||||
#E ((..)|(.)){3} aaaaa (0,5)(4,5)(?,?)(4,5)
|
||||
E ((..)|(.)){3} aaaaa (0,5)(4,5)(2,4)(4,5) RE2/Go
|
||||
|
||||
#E ((..)|(.))* aaaaa (0,5)(4,5)(?,?)(4,5)
|
||||
E ((..)|(.))* aaaaa (0,5)(4,5)(2,4)(4,5) RE2/Go
|
||||
|
||||
E ((..)|(.)) aaaaaa (0,2)(0,2)(0,2)(?,?)
|
||||
E ((..)|(.))((..)|(.)) aaaaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
|
||||
E ((..)|(.))((..)|(.))((..)|(.)) aaaaaa (0,6)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)(4,6)(4,6)(?,?)
|
||||
|
||||
E ((..)|(.)){1} aaaaaa (0,2)(0,2)(0,2)(?,?)
|
||||
E ((..)|(.)){2} aaaaaa (0,4)(2,4)(2,4)(?,?)
|
||||
E ((..)|(.)){3} aaaaaa (0,6)(4,6)(4,6)(?,?)
|
||||
|
||||
E ((..)|(.))* aaaaaa (0,6)(4,6)(4,6)(?,?)
|
||||
|
||||
NOTE additional repetition tests graciously provided by Chris Kuklewicz www.haskell.org 2009-02-02
|
||||
|
||||
# These test a bug in OS X / FreeBSD / NetBSD, and libtree.
|
||||
# Linux/GLIBC gets the {8,} and {8,8} wrong.
|
||||
|
||||
:HA#100:E X(.?){0,}Y X1234567Y (0,9)(7,8)
|
||||
:HA#101:E X(.?){1,}Y X1234567Y (0,9)(7,8)
|
||||
:HA#102:E X(.?){2,}Y X1234567Y (0,9)(7,8)
|
||||
:HA#103:E X(.?){3,}Y X1234567Y (0,9)(7,8)
|
||||
:HA#104:E X(.?){4,}Y X1234567Y (0,9)(7,8)
|
||||
:HA#105:E X(.?){5,}Y X1234567Y (0,9)(7,8)
|
||||
:HA#106:E X(.?){6,}Y X1234567Y (0,9)(7,8)
|
||||
:HA#107:E X(.?){7,}Y X1234567Y (0,9)(7,8)
|
||||
:HA#108:E X(.?){8,}Y X1234567Y (0,9)(8,8)
|
||||
#:HA#110:E X(.?){0,8}Y X1234567Y (0,9)(7,8)
|
||||
:HA#110:E X(.?){0,8}Y X1234567Y (0,9)(8,8) RE2/Go
|
||||
#:HA#111:E X(.?){1,8}Y X1234567Y (0,9)(7,8)
|
||||
:HA#111:E X(.?){1,8}Y X1234567Y (0,9)(8,8) RE2/Go
|
||||
#:HA#112:E X(.?){2,8}Y X1234567Y (0,9)(7,8)
|
||||
:HA#112:E X(.?){2,8}Y X1234567Y (0,9)(8,8) RE2/Go
|
||||
#:HA#113:E X(.?){3,8}Y X1234567Y (0,9)(7,8)
|
||||
:HA#113:E X(.?){3,8}Y X1234567Y (0,9)(8,8) RE2/Go
|
||||
#:HA#114:E X(.?){4,8}Y X1234567Y (0,9)(7,8)
|
||||
:HA#114:E X(.?){4,8}Y X1234567Y (0,9)(8,8) RE2/Go
|
||||
#:HA#115:E X(.?){5,8}Y X1234567Y (0,9)(7,8)
|
||||
:HA#115:E X(.?){5,8}Y X1234567Y (0,9)(8,8) RE2/Go
|
||||
#:HA#116:E X(.?){6,8}Y X1234567Y (0,9)(7,8)
|
||||
:HA#116:E X(.?){6,8}Y X1234567Y (0,9)(8,8) RE2/Go
|
||||
#:HA#117:E X(.?){7,8}Y X1234567Y (0,9)(7,8)
|
||||
:HA#117:E X(.?){7,8}Y X1234567Y (0,9)(8,8) RE2/Go
|
||||
:HA#118:E X(.?){8,8}Y X1234567Y (0,9)(8,8)
|
||||
|
||||
# These test a fixed bug in my regex-tdfa that did not keep the expanded
|
||||
# form properly grouped, so right association did the wrong thing with
|
||||
# these ambiguous patterns (crafted just to test my code when I became
|
||||
# suspicious of my implementation). The first subexpression should use
|
||||
# "ab" then "a" then "bcd".
|
||||
|
||||
# OS X / FreeBSD / NetBSD badly fail many of these, with impossible
|
||||
# results like (0,6)(4,5)(6,6).
|
||||
|
||||
:HA#260:E (a|ab|c|bcd){0,}(d*) ababcd (0,1)(0,1)(1,1)
|
||||
:HA#261:E (a|ab|c|bcd){1,}(d*) ababcd (0,1)(0,1)(1,1)
|
||||
:HA#262:E (a|ab|c|bcd){2,}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#263:E (a|ab|c|bcd){3,}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#264:E (a|ab|c|bcd){4,}(d*) ababcd NOMATCH
|
||||
:HA#265:E (a|ab|c|bcd){0,10}(d*) ababcd (0,1)(0,1)(1,1)
|
||||
:HA#266:E (a|ab|c|bcd){1,10}(d*) ababcd (0,1)(0,1)(1,1)
|
||||
:HA#267:E (a|ab|c|bcd){2,10}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#268:E (a|ab|c|bcd){3,10}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#269:E (a|ab|c|bcd){4,10}(d*) ababcd NOMATCH
|
||||
:HA#270:E (a|ab|c|bcd)*(d*) ababcd (0,1)(0,1)(1,1)
|
||||
:HA#271:E (a|ab|c|bcd)+(d*) ababcd (0,1)(0,1)(1,1)
|
||||
|
||||
# The above worked on Linux/GLIBC but the following often fail.
|
||||
# They also trip up OS X / FreeBSD / NetBSD:
|
||||
|
||||
#:HA#280:E (ab|a|c|bcd){0,}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#280:E (ab|a|c|bcd){0,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
|
||||
#:HA#281:E (ab|a|c|bcd){1,}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#281:E (ab|a|c|bcd){1,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
|
||||
#:HA#282:E (ab|a|c|bcd){2,}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#282:E (ab|a|c|bcd){2,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
|
||||
#:HA#283:E (ab|a|c|bcd){3,}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#283:E (ab|a|c|bcd){3,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
|
||||
:HA#284:E (ab|a|c|bcd){4,}(d*) ababcd NOMATCH
|
||||
#:HA#285:E (ab|a|c|bcd){0,10}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#285:E (ab|a|c|bcd){0,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
|
||||
#:HA#286:E (ab|a|c|bcd){1,10}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#286:E (ab|a|c|bcd){1,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
|
||||
#:HA#287:E (ab|a|c|bcd){2,10}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#287:E (ab|a|c|bcd){2,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
|
||||
#:HA#288:E (ab|a|c|bcd){3,10}(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#288:E (ab|a|c|bcd){3,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
|
||||
:HA#289:E (ab|a|c|bcd){4,10}(d*) ababcd NOMATCH
|
||||
#:HA#290:E (ab|a|c|bcd)*(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#290:E (ab|a|c|bcd)*(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
|
||||
#:HA#291:E (ab|a|c|bcd)+(d*) ababcd (0,6)(3,6)(6,6)
|
||||
:HA#291:E (ab|a|c|bcd)+(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
|
@ -1,582 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// FIXME: Currently, the VM simulates an NFA. It would be nice to have another
|
||||
// VM that simulates a DFA.
|
||||
//
|
||||
// According to Russ Cox[1], a DFA performs better than an NFA, principally
|
||||
// because it reuses states previously computed by the machine *and* doesn't
|
||||
// keep track of capture groups. The drawback of a DFA (aside from its
|
||||
// complexity) is that it can't accurately return the locations of submatches.
|
||||
// The NFA *can* do that. (This is my understanding anyway.)
|
||||
//
|
||||
// Cox suggests that a DFA ought to be used to answer "does this match" and
|
||||
// "where does it match" questions. (In the latter, the starting position of
|
||||
// the match is computed by executing the regex backwards.) Cox also suggests
|
||||
// that a DFA should be run when asking "where are the submatches", which can
|
||||
// 1) quickly answer "no" is there's no match and 2) discover the substring
|
||||
// that matches, which means running the NFA on smaller input.
|
||||
//
|
||||
// Currently, the NFA simulation implemented below does some dirty tricks to
|
||||
// avoid tracking capture groups when they aren't needed (which only works
|
||||
// for 'is_match', not 'find'). This is a half-measure, but does provide some
|
||||
// perf improvement.
|
||||
//
|
||||
// AFAIK, the DFA/NFA approach is implemented in RE2/C++ but *not* in RE2/Go.
|
||||
//
|
||||
// [1] - http://swtch.com/~rsc/regex/regex3.html
|
||||
|
||||
pub use self::MatchKind::*;
|
||||
pub use self::StepState::*;
|
||||
|
||||
use std::cmp;
|
||||
use std::cmp::Ordering::{self, Less, Equal, Greater};
|
||||
use std::mem;
|
||||
use std::iter::repeat;
|
||||
use std::slice::SliceExt;
|
||||
use compile::{
|
||||
Program,
|
||||
Match, OneChar, CharClass, Any, EmptyBegin, EmptyEnd, EmptyWordBoundary,
|
||||
Save, Jump, Split,
|
||||
};
|
||||
use parse::{FLAG_NOCASE, FLAG_MULTI, FLAG_DOTNL, FLAG_NEGATED};
|
||||
use unicode::regex::PERLW;
|
||||
|
||||
pub type CaptureLocs = Vec<Option<uint>>;
|
||||
|
||||
/// Indicates the type of match to be performed by the VM.
|
||||
#[derive(Copy)]
|
||||
pub enum MatchKind {
|
||||
/// Only checks if a match exists or not. Does not return location.
|
||||
Exists,
|
||||
/// Returns the start and end indices of the entire match in the input
|
||||
/// given.
|
||||
Location,
|
||||
/// Returns the start and end indices of each submatch in the input given.
|
||||
Submatches,
|
||||
}
|
||||
|
||||
/// Runs an NFA simulation on the compiled expression given on the search text
|
||||
/// `input`. The search begins at byte index `start` and ends at byte index
|
||||
/// `end`. (The range is specified here so that zero-width assertions will work
|
||||
/// correctly when searching for successive non-overlapping matches.)
|
||||
///
|
||||
/// The `which` parameter indicates what kind of capture information the caller
|
||||
/// wants. There are three choices: match existence only, the location of the
|
||||
/// entire match or the locations of the entire match in addition to the
|
||||
/// locations of each submatch.
|
||||
pub fn run<'r, 't>(which: MatchKind, prog: &'r Program, input: &'t str,
|
||||
start: uint, end: uint) -> CaptureLocs {
|
||||
Nfa {
|
||||
which: which,
|
||||
prog: prog,
|
||||
input: input,
|
||||
start: start,
|
||||
end: end,
|
||||
ic: 0,
|
||||
chars: CharReader::new(input),
|
||||
}.run()
|
||||
}
|
||||
|
||||
struct Nfa<'r, 't> {
|
||||
which: MatchKind,
|
||||
prog: &'r Program,
|
||||
input: &'t str,
|
||||
start: uint,
|
||||
end: uint,
|
||||
ic: uint,
|
||||
chars: CharReader<'t>,
|
||||
}
|
||||
|
||||
/// Indicates the next action to take after a single non-empty instruction
|
||||
/// is processed.
|
||||
#[derive(Copy)]
|
||||
pub enum StepState {
|
||||
/// This is returned if and only if a Match instruction is reached and
|
||||
/// we only care about the existence of a match. It instructs the VM to
|
||||
/// quit early.
|
||||
StepMatchEarlyReturn,
|
||||
/// Indicates that a match was found. Thus, the rest of the states in the
|
||||
/// *current* queue should be dropped (i.e., leftmost-first semantics).
|
||||
/// States in the "next" queue can still be processed.
|
||||
StepMatch,
|
||||
/// No match was found. Continue with the next state in the queue.
|
||||
StepContinue,
|
||||
}
|
||||
|
||||
impl<'r, 't> Nfa<'r, 't> {
|
||||
fn run(&mut self) -> CaptureLocs {
|
||||
let ncaps = match self.which {
|
||||
Exists => 0,
|
||||
Location => 1,
|
||||
Submatches => self.prog.num_captures(),
|
||||
};
|
||||
let mut matched = false;
|
||||
let ninsts = self.prog.insts.len();
|
||||
let mut clist = &mut Threads::new(self.which, ninsts, ncaps);
|
||||
let mut nlist = &mut Threads::new(self.which, ninsts, ncaps);
|
||||
|
||||
let mut groups: Vec<_> = repeat(None).take(ncaps * 2).collect();
|
||||
|
||||
// Determine if the expression starts with a '^' so we can avoid
|
||||
// simulating .*?
|
||||
// Make sure multi-line mode isn't enabled for it, otherwise we can't
|
||||
// drop the initial .*?
|
||||
let prefix_anchor =
|
||||
match self.prog.insts[1] {
|
||||
EmptyBegin(flags) if flags & FLAG_MULTI == 0 => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
self.ic = self.start;
|
||||
let mut next_ic = self.chars.set(self.start);
|
||||
while self.ic <= self.end {
|
||||
if clist.size == 0 {
|
||||
// We have a match and we're done exploring alternatives.
|
||||
// Time to quit.
|
||||
if matched {
|
||||
break
|
||||
}
|
||||
|
||||
// If there are no threads to try, then we'll have to start
|
||||
// over at the beginning of the regex.
|
||||
// BUT, if there's a literal prefix for the program, try to
|
||||
// jump ahead quickly. If it can't be found, then we can bail
|
||||
// out early.
|
||||
if self.prog.prefix.len() > 0 && clist.size == 0 {
|
||||
let needle = self.prog.prefix.as_bytes();
|
||||
let haystack = &self.input.as_bytes()[self.ic..];
|
||||
match find_prefix(needle, haystack) {
|
||||
None => break,
|
||||
Some(i) => {
|
||||
self.ic += i;
|
||||
next_ic = self.chars.set(self.ic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This simulates a preceding '.*?' for every regex by adding
|
||||
// a state starting at the current position in the input for the
|
||||
// beginning of the program only if we don't already have a match.
|
||||
if clist.size == 0 || (!prefix_anchor && !matched) {
|
||||
self.add(clist, 0, groups.as_mut_slice())
|
||||
}
|
||||
|
||||
// Now we try to read the next character.
|
||||
// As a result, the 'step' method will look at the previous
|
||||
// character.
|
||||
self.ic = next_ic;
|
||||
next_ic = self.chars.advance();
|
||||
|
||||
for i in range(0, clist.size) {
|
||||
let pc = clist.pc(i);
|
||||
let step_state = self.step(groups.as_mut_slice(), nlist,
|
||||
clist.groups(i), pc);
|
||||
match step_state {
|
||||
StepMatchEarlyReturn => return vec![Some(0), Some(0)],
|
||||
StepMatch => { matched = true; break },
|
||||
StepContinue => {},
|
||||
}
|
||||
}
|
||||
mem::swap(&mut clist, &mut nlist);
|
||||
nlist.empty();
|
||||
}
|
||||
match self.which {
|
||||
Exists if matched => vec![Some(0), Some(0)],
|
||||
Exists => vec![None, None],
|
||||
Location | Submatches => groups,
|
||||
}
|
||||
}
|
||||
|
||||
fn step(&self, groups: &mut [Option<uint>], nlist: &mut Threads,
|
||||
caps: &mut [Option<uint>], pc: uint)
|
||||
-> StepState {
|
||||
match self.prog.insts[pc] {
|
||||
Match => {
|
||||
match self.which {
|
||||
Exists => {
|
||||
return StepMatchEarlyReturn
|
||||
}
|
||||
Location => {
|
||||
groups[0] = caps[0];
|
||||
groups[1] = caps[1];
|
||||
return StepMatch
|
||||
}
|
||||
Submatches => {
|
||||
for (slot, val) in groups.iter_mut().zip(caps.iter()) {
|
||||
*slot = *val;
|
||||
}
|
||||
return StepMatch
|
||||
}
|
||||
}
|
||||
}
|
||||
OneChar(c, flags) => {
|
||||
if self.char_eq(flags & FLAG_NOCASE > 0, self.chars.prev, c) {
|
||||
self.add(nlist, pc+1, caps);
|
||||
}
|
||||
}
|
||||
CharClass(ref ranges, flags) => {
|
||||
if self.chars.prev.is_some() {
|
||||
let c = self.chars.prev.unwrap();
|
||||
let negate = flags & FLAG_NEGATED > 0;
|
||||
let casei = flags & FLAG_NOCASE > 0;
|
||||
let found = ranges.as_slice();
|
||||
let found = found.binary_search_by(|&rc| class_cmp(casei, c, rc)).is_ok();
|
||||
if found ^ negate {
|
||||
self.add(nlist, pc+1, caps);
|
||||
}
|
||||
}
|
||||
}
|
||||
Any(flags) => {
|
||||
if flags & FLAG_DOTNL > 0
|
||||
|| !self.char_eq(false, self.chars.prev, '\n') {
|
||||
self.add(nlist, pc+1, caps)
|
||||
}
|
||||
}
|
||||
EmptyBegin(_) | EmptyEnd(_) | EmptyWordBoundary(_)
|
||||
| Save(_) | Jump(_) | Split(_, _) => {},
|
||||
}
|
||||
StepContinue
|
||||
}
|
||||
|
||||
fn add(&self, nlist: &mut Threads, pc: uint, groups: &mut [Option<uint>]) {
|
||||
if nlist.contains(pc) {
|
||||
return
|
||||
}
|
||||
// We have to add states to the threads list even if their empty.
|
||||
// TL;DR - It prevents cycles.
|
||||
// If we didn't care about cycles, we'd *only* add threads that
|
||||
// correspond to non-jumping instructions (OneChar, Any, Match, etc.).
|
||||
// But, it's possible for valid regexs (like '(a*)*') to result in
|
||||
// a cycle in the instruction list. e.g., We'll keep chasing the Split
|
||||
// instructions forever.
|
||||
// So we add these instructions to our thread queue, but in the main
|
||||
// VM loop, we look for them but simply ignore them.
|
||||
// Adding them to the queue prevents them from being revisited so we
|
||||
// can avoid cycles (and the inevitable stack overflow).
|
||||
//
|
||||
// We make a minor optimization by indicating that the state is "empty"
|
||||
// so that its capture groups are not filled in.
|
||||
match self.prog.insts[pc] {
|
||||
EmptyBegin(flags) => {
|
||||
let multi = flags & FLAG_MULTI > 0;
|
||||
nlist.add(pc, groups, true);
|
||||
if self.chars.is_begin()
|
||||
|| (multi && self.char_is(self.chars.prev, '\n')) {
|
||||
self.add(nlist, pc + 1, groups)
|
||||
}
|
||||
}
|
||||
EmptyEnd(flags) => {
|
||||
let multi = flags & FLAG_MULTI > 0;
|
||||
nlist.add(pc, groups, true);
|
||||
if self.chars.is_end()
|
||||
|| (multi && self.char_is(self.chars.cur, '\n')) {
|
||||
self.add(nlist, pc + 1, groups)
|
||||
}
|
||||
}
|
||||
EmptyWordBoundary(flags) => {
|
||||
nlist.add(pc, groups, true);
|
||||
if self.chars.is_word_boundary() == !(flags & FLAG_NEGATED > 0) {
|
||||
self.add(nlist, pc + 1, groups)
|
||||
}
|
||||
}
|
||||
Save(slot) => {
|
||||
nlist.add(pc, groups, true);
|
||||
match self.which {
|
||||
Location if slot <= 1 => {
|
||||
let old = groups[slot];
|
||||
groups[slot] = Some(self.ic);
|
||||
self.add(nlist, pc + 1, groups);
|
||||
groups[slot] = old;
|
||||
}
|
||||
Submatches => {
|
||||
let old = groups[slot];
|
||||
groups[slot] = Some(self.ic);
|
||||
self.add(nlist, pc + 1, groups);
|
||||
groups[slot] = old;
|
||||
}
|
||||
Exists | Location => self.add(nlist, pc + 1, groups),
|
||||
}
|
||||
}
|
||||
Jump(to) => {
|
||||
nlist.add(pc, groups, true);
|
||||
self.add(nlist, to, groups)
|
||||
}
|
||||
Split(x, y) => {
|
||||
nlist.add(pc, groups, true);
|
||||
self.add(nlist, x, groups);
|
||||
self.add(nlist, y, groups);
|
||||
}
|
||||
Match | OneChar(_, _) | CharClass(_, _) | Any(_) => {
|
||||
nlist.add(pc, groups, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: For case insensitive comparisons, it uses the uppercase
|
||||
// character and tests for equality. IIUC, this does not generalize to
|
||||
// all of Unicode. I believe we need to check the entire fold for each
|
||||
// character. This will be easy to add if and when it gets added to Rust's
|
||||
// standard library.
|
||||
#[inline]
|
||||
fn char_eq(&self, casei: bool, textc: Option<char>, regc: char) -> bool {
|
||||
match textc {
|
||||
None => false,
|
||||
Some(textc) => {
|
||||
regc == textc
|
||||
|| (casei && regc.to_uppercase() == textc.to_uppercase())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn char_is(&self, textc: Option<char>, regc: char) -> bool {
|
||||
textc == Some(regc)
|
||||
}
|
||||
}
|
||||
|
||||
/// CharReader is responsible for maintaining a "previous" and a "current"
|
||||
/// character. This one-character lookahead is necessary for assertions that
|
||||
/// look one character before or after the current position.
|
||||
pub struct CharReader<'t> {
|
||||
/// The previous character read. It is None only when processing the first
|
||||
/// character of the input.
|
||||
pub prev: Option<char>,
|
||||
/// The current character.
|
||||
pub cur: Option<char>,
|
||||
input: &'t str,
|
||||
next: uint,
|
||||
}
|
||||
|
||||
impl<'t> CharReader<'t> {
|
||||
/// Returns a new CharReader that advances through the input given.
|
||||
/// Note that a CharReader has no knowledge of the range in which to search
|
||||
/// the input.
|
||||
pub fn new(input: &'t str) -> CharReader<'t> {
|
||||
CharReader {
|
||||
prev: None,
|
||||
cur: None,
|
||||
input: input,
|
||||
next: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the previous and current character given any arbitrary byte
|
||||
/// index (at a Unicode codepoint boundary).
|
||||
#[inline]
|
||||
pub fn set(&mut self, ic: uint) -> uint {
|
||||
self.prev = None;
|
||||
self.cur = None;
|
||||
self.next = 0;
|
||||
|
||||
if self.input.len() == 0 {
|
||||
return 1
|
||||
}
|
||||
if ic > 0 {
|
||||
let i = cmp::min(ic, self.input.len());
|
||||
let prev = self.input.char_range_at_reverse(i);
|
||||
self.prev = Some(prev.ch);
|
||||
}
|
||||
if ic < self.input.len() {
|
||||
let cur = self.input.char_range_at(ic);
|
||||
self.cur = Some(cur.ch);
|
||||
self.next = cur.next;
|
||||
self.next
|
||||
} else {
|
||||
self.input.len() + 1
|
||||
}
|
||||
}
|
||||
|
||||
/// Does the same as `set`, except it always advances to the next
|
||||
/// character in the input (and therefore does half as many UTF8 decodings).
|
||||
#[inline]
|
||||
pub fn advance(&mut self) -> uint {
|
||||
self.prev = self.cur;
|
||||
if self.next < self.input.len() {
|
||||
let cur = self.input.char_range_at(self.next);
|
||||
self.cur = Some(cur.ch);
|
||||
self.next = cur.next;
|
||||
} else {
|
||||
self.cur = None;
|
||||
self.next = self.input.len() + 1;
|
||||
}
|
||||
self.next
|
||||
}
|
||||
|
||||
/// Returns true if and only if this is the beginning of the input
|
||||
/// (ignoring the range of the input to search).
|
||||
#[inline]
|
||||
pub fn is_begin(&self) -> bool { self.prev.is_none() }
|
||||
|
||||
/// Returns true if and only if this is the end of the input
|
||||
/// (ignoring the range of the input to search).
|
||||
#[inline]
|
||||
pub fn is_end(&self) -> bool { self.cur.is_none() }
|
||||
|
||||
/// Returns true if and only if the current position is a word boundary.
|
||||
/// (Ignoring the range of the input to search.)
|
||||
pub fn is_word_boundary(&self) -> bool {
|
||||
if self.is_begin() {
|
||||
return is_word(self.cur)
|
||||
}
|
||||
if self.is_end() {
|
||||
return is_word(self.prev)
|
||||
}
|
||||
(is_word(self.cur) && !is_word(self.prev))
|
||||
|| (is_word(self.prev) && !is_word(self.cur))
|
||||
}
|
||||
}
|
||||
|
||||
struct Thread {
|
||||
pc: uint,
|
||||
groups: Vec<Option<uint>>,
|
||||
}
|
||||
|
||||
struct Threads {
|
||||
which: MatchKind,
|
||||
queue: Vec<Thread>,
|
||||
sparse: Vec<uint>,
|
||||
size: uint,
|
||||
}
|
||||
|
||||
impl Threads {
|
||||
// This is using a wicked neat trick to provide constant time lookup
|
||||
// for threads in the queue using a sparse set. A queue of threads is
|
||||
// allocated once with maximal size when the VM initializes and is reused
|
||||
// throughout execution. That is, there should be zero allocation during
|
||||
// the execution of a VM.
|
||||
//
|
||||
// See http://research.swtch.com/sparse for the deets.
|
||||
fn new(which: MatchKind, num_insts: uint, ncaps: uint) -> Threads {
|
||||
Threads {
|
||||
which: which,
|
||||
queue: range(0, num_insts).map(|_| {
|
||||
Thread { pc: 0, groups: repeat(None).take(ncaps * 2).collect() }
|
||||
}).collect(),
|
||||
sparse: repeat(0u).take(num_insts).collect(),
|
||||
size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&mut self, pc: uint, groups: &[Option<uint>], empty: bool) {
|
||||
let t = &mut self.queue[self.size];
|
||||
t.pc = pc;
|
||||
match (empty, self.which) {
|
||||
(_, Exists) | (true, _) => {},
|
||||
(false, Location) => {
|
||||
t.groups[0] = groups[0];
|
||||
t.groups[1] = groups[1];
|
||||
}
|
||||
(false, Submatches) => {
|
||||
for (slot, val) in t.groups.iter_mut().zip(groups.iter()) {
|
||||
*slot = *val;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.sparse[pc] = self.size;
|
||||
self.size += 1;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn contains(&self, pc: uint) -> bool {
|
||||
let s = self.sparse[pc];
|
||||
s < self.size && self.queue[s].pc == pc
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn empty(&mut self) {
|
||||
self.size = 0;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pc(&self, i: uint) -> uint {
|
||||
self.queue[i].pc
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn groups<'r>(&'r mut self, i: uint) -> &'r mut [Option<uint>] {
|
||||
let q = &mut self.queue[i];
|
||||
q.groups.as_mut_slice()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the character is a word character, according to the
|
||||
/// (Unicode friendly) Perl character class '\w'.
|
||||
/// Note that this is only use for testing word boundaries. The actual '\w'
|
||||
/// is encoded as a CharClass instruction.
|
||||
pub fn is_word(c: Option<char>) -> bool {
|
||||
let c = match c {
|
||||
None => return false,
|
||||
Some(c) => c,
|
||||
};
|
||||
// Try the common ASCII case before invoking binary search.
|
||||
match c {
|
||||
'_' | '0' ... '9' | 'a' ... 'z' | 'A' ... 'Z' => true,
|
||||
_ => PERLW.binary_search_by(|&(start, end)| {
|
||||
if c >= start && c <= end {
|
||||
Equal
|
||||
} else if start > c {
|
||||
Greater
|
||||
} else {
|
||||
Less
|
||||
}
|
||||
}).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a character and a single character class range, return an ordering
|
||||
/// indicating whether the character is less than the start of the range,
|
||||
/// in the range (inclusive) or greater than the end of the range.
|
||||
///
|
||||
/// If `casei` is `true`, then this ordering is computed case insensitively.
|
||||
///
|
||||
/// This function is meant to be used with a binary search.
|
||||
#[inline]
|
||||
fn class_cmp(casei: bool, mut textc: char,
|
||||
(mut start, mut end): (char, char)) -> Ordering {
|
||||
if casei {
|
||||
// FIXME: This is pretty ridiculous. All of this case conversion
|
||||
// can be moved outside this function:
|
||||
// 1) textc should be uppercased outside the bsearch.
|
||||
// 2) the character class itself should be uppercased either in the
|
||||
// parser or the compiler.
|
||||
// FIXME: This is too simplistic for correct Unicode support.
|
||||
// See also: char_eq
|
||||
textc = textc.to_uppercase();
|
||||
start = start.to_uppercase();
|
||||
end = end.to_uppercase();
|
||||
}
|
||||
if textc >= start && textc <= end {
|
||||
Equal
|
||||
} else if start > textc {
|
||||
Greater
|
||||
} else {
|
||||
Less
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the starting location of `needle` in `haystack`.
|
||||
/// If `needle` is not in `haystack`, then `None` is returned.
|
||||
///
|
||||
/// Note that this is using a naive substring algorithm.
|
||||
#[inline]
|
||||
pub fn find_prefix(needle: &[u8], haystack: &[u8]) -> Option<uint> {
|
||||
let (hlen, nlen) = (haystack.len(), needle.len());
|
||||
if nlen > hlen || nlen == 0 {
|
||||
return None
|
||||
}
|
||||
for (offset, window) in haystack.windows(nlen).enumerate() {
|
||||
if window == needle {
|
||||
return Some(offset)
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
@ -10,28 +10,55 @@
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
register_diagnostic! { E0001, r##"
|
||||
register_long_diagnostics! {
|
||||
E0001: r##"
|
||||
This error suggests that the expression arm corresponding to the noted pattern
|
||||
will never be reached as for all possible values of the expression being matched,
|
||||
one of the preceeding patterns will match.
|
||||
|
||||
This means that perhaps some of the preceeding patterns are too general, this
|
||||
one is too specific or the ordering is incorrect.
|
||||
"## }
|
||||
"##,
|
||||
|
||||
E0003: r##"
|
||||
Not-a-Number (NaN) values can not be compared for equality and hence can never match
|
||||
the input to a match expression. To match against NaN values, you should instead use
|
||||
the `is_nan` method in a guard, as in: x if x.is_nan() => ...
|
||||
"##,
|
||||
|
||||
E0004: r##"
|
||||
This error indicates that the compiler can not guarantee a matching pattern for one
|
||||
or more possible inputs to a match expression. Guaranteed matches are required in order
|
||||
to assign values to match expressions, or alternatively, determine the flow of execution.
|
||||
|
||||
If you encounter this error you must alter your patterns so that every possible value of
|
||||
the input type is matched. For types with a small number of variants (like enums) you
|
||||
should probably cover all cases explicitly. Alternatively, the underscore `_` wildcard
|
||||
pattern can be added after all other patterns to match "anything else".
|
||||
"##,
|
||||
|
||||
// FIXME: Remove duplication here?
|
||||
E0005: r##"
|
||||
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
|
||||
name will be extracted in all cases. If you encounter this error you probably need
|
||||
to use a `match` or `if let` to deal with the possibility of failure.
|
||||
"##,
|
||||
|
||||
E0006: r##"
|
||||
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
|
||||
name will be extracted in all cases. If you encounter this error you probably need
|
||||
to use a `match` or `if let` to deal with the possibility of failure.
|
||||
"##
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
E0002,
|
||||
E0003,
|
||||
E0004,
|
||||
E0005,
|
||||
E0006,
|
||||
E0007,
|
||||
E0008,
|
||||
E0009,
|
||||
E0010,
|
||||
E0011,
|
||||
E0012,
|
||||
E0013,
|
||||
E0014,
|
||||
E0015,
|
||||
E0016,
|
||||
@ -49,24 +76,58 @@ register_diagnostics! {
|
||||
E0137,
|
||||
E0138,
|
||||
E0139,
|
||||
E0140,
|
||||
E0152,
|
||||
E0153,
|
||||
E0157,
|
||||
E0158,
|
||||
E0161,
|
||||
E0162,
|
||||
E0165,
|
||||
E0166,
|
||||
E0167,
|
||||
E0168,
|
||||
E0169,
|
||||
E0170,
|
||||
E0171,
|
||||
E0172,
|
||||
E0173,
|
||||
E0174,
|
||||
E0177,
|
||||
E0178,
|
||||
E0179
|
||||
E0261, // use of undeclared lifetime name
|
||||
E0262, // illegal lifetime parameter name
|
||||
E0263, // lifetime name declared twice in same scope
|
||||
E0264, // unknown external lang item
|
||||
E0265, // recursive constant
|
||||
E0266, // expected item
|
||||
E0267, // thing inside of a closure
|
||||
E0268, // thing outside of a loop
|
||||
E0269, // not all control paths return a value
|
||||
E0270, // computation may converge in a function marked as diverging
|
||||
E0271, // type mismatch resolving
|
||||
E0272, // rustc_on_unimplemented attribute refers to non-existent type parameter
|
||||
E0273, // rustc_on_unimplemented must have named format arguments
|
||||
E0274, // rustc_on_unimplemented must have a value
|
||||
E0275, // overflow evaluating requirement
|
||||
E0276, // requirement appears on impl method but not on corresponding trait method
|
||||
E0277, // trait is not implemented for type
|
||||
E0278, // requirement is not satisfied
|
||||
E0279, // requirement is not satisfied
|
||||
E0280, // requirement is not satisfied
|
||||
E0281, // type implements trait but other trait is required
|
||||
E0282, // unable to infer enough type information about
|
||||
E0283, // cannot resolve type
|
||||
E0284, // cannot resolve type
|
||||
E0285, // overflow evaluation builtin bounds
|
||||
E0296, // malformed recursion limit attribute
|
||||
E0297, // refutable pattern in for loop binding
|
||||
E0298, // mismatched types between arms
|
||||
E0299, // mismatched types between arms
|
||||
E0300, // unexpanded macro
|
||||
E0301, // cannot mutable borrow in a pattern guard
|
||||
E0302, // cannot assign in a pattern guard
|
||||
E0303, // pattern bindings are not allowed after an `@`
|
||||
E0304, // expected signed integer constant
|
||||
E0305, // expected constant
|
||||
E0306, // expected positive integer for repeat count
|
||||
E0307, // expected constant integer for repeat count
|
||||
E0308,
|
||||
E0309, // thing may not live long enough
|
||||
E0310, // thing may not live long enough
|
||||
E0311, // thing may not live long enough
|
||||
E0312, // lifetime of reference outlives lifetime of borrowed content
|
||||
E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
|
||||
E0314, // closure outlives stack frame
|
||||
E0315 // cannot invoke closure outside of its lifetime
|
||||
}
|
||||
|
||||
__build_diagnostic_array! { DIAGNOSTICS }
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#![feature(std_misc)]
|
||||
#![feature(unicode)]
|
||||
#![feature(hash)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
|
||||
extern crate arena;
|
||||
extern crate flate;
|
||||
@ -47,7 +48,6 @@ extern crate fmt_macros;
|
||||
extern crate getopts;
|
||||
extern crate graphviz;
|
||||
extern crate libc;
|
||||
extern crate regex;
|
||||
extern crate rustc_llvm;
|
||||
extern crate rustc_back;
|
||||
extern crate serialize;
|
||||
@ -64,7 +64,9 @@ extern crate test;
|
||||
|
||||
pub use rustc_llvm as llvm;
|
||||
|
||||
mod diagnostics;
|
||||
// NB: This module needs to be declared first so diagnostics are
|
||||
// registered before they are used.
|
||||
pub mod diagnostics;
|
||||
|
||||
pub mod back {
|
||||
pub use rustc_back::abi;
|
||||
@ -142,8 +144,6 @@ pub mod lib {
|
||||
pub use llvm;
|
||||
}
|
||||
|
||||
__build_diagnostic_array! { DIAGNOSTICS }
|
||||
|
||||
// A private module so that macro-expanded idents like
|
||||
// `::rustc::lint::Lint` will also work in `rustc` itself.
|
||||
//
|
||||
|
@ -1199,17 +1199,17 @@ impl LintPass for UnusedImportBraces {
|
||||
lint_array!(UNUSED_IMPORT_BRACES)
|
||||
}
|
||||
|
||||
fn check_view_item(&mut self, cx: &Context, view_item: &ast::ViewItem) {
|
||||
match view_item.node {
|
||||
ast::ViewItemUse(ref view_path) => {
|
||||
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
|
||||
match item.node {
|
||||
ast::ItemUse(ref view_path) => {
|
||||
match view_path.node {
|
||||
ast::ViewPathList(_, ref items, _) => {
|
||||
ast::ViewPathList(_, ref items) => {
|
||||
if items.len() == 1 {
|
||||
match items[0].node {
|
||||
ast::PathListIdent {ref name, ..} => {
|
||||
let m = format!("braces around {} is unnecessary",
|
||||
token::get_ident(*name).get());
|
||||
cx.span_lint(UNUSED_IMPORT_BRACES, view_item.span,
|
||||
cx.span_lint(UNUSED_IMPORT_BRACES, item.span,
|
||||
&m[]);
|
||||
},
|
||||
_ => ()
|
||||
@ -1326,7 +1326,7 @@ impl UnusedMut {
|
||||
let ident = path1.node;
|
||||
if let ast::BindByValue(ast::MutMutable) = mode {
|
||||
if !token::get_ident(ident).get().starts_with("_") {
|
||||
match mutables.entry(ident.name.uint()) {
|
||||
match mutables.entry(ident.name.usize()) {
|
||||
Vacant(entry) => { entry.insert(vec![id]); },
|
||||
Occupied(mut entry) => { entry.get_mut().push(id); },
|
||||
}
|
||||
@ -1663,11 +1663,6 @@ impl LintPass for Stability {
|
||||
lint_array!(DEPRECATED)
|
||||
}
|
||||
|
||||
fn check_view_item(&mut self, cx: &Context, item: &ast::ViewItem) {
|
||||
stability::check_view_item(cx.tcx, item,
|
||||
&mut |id, sp, stab| self.lint(cx, id, sp, stab));
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
|
||||
stability::check_item(cx.tcx, item,
|
||||
&mut |id, sp, stab| self.lint(cx, id, sp, stab));
|
||||
|
@ -231,30 +231,7 @@ impl LintStore {
|
||||
// We have one lint pass defined in this module.
|
||||
self.register_pass(sess, false, box GatherNodeLevels as LintPassObject);
|
||||
|
||||
// Insert temporary renamings for a one-time deprecation (#16545)
|
||||
self.register_renamed("unnecessary_typecast", "unused_typecasts");
|
||||
self.register_renamed("unsigned_negate", "unsigned_negation");
|
||||
self.register_renamed("type_limits", "unused_comparisons");
|
||||
self.register_renamed("type_overflow", "overflowing_literals");
|
||||
self.register_renamed("ctypes", "improper_ctypes");
|
||||
self.register_renamed("owned_heap_memory", "box_pointers");
|
||||
self.register_renamed("unused_attribute", "unused_attributes");
|
||||
self.register_renamed("path_statement", "path_statements");
|
||||
self.register_renamed("unused_result", "unused_results");
|
||||
self.register_renamed("non_uppercase_statics", "non_upper_case_globals");
|
||||
self.register_renamed("unnecessary_parens", "unused_parens");
|
||||
self.register_renamed("unnecessary_import_braces", "unused_import_braces");
|
||||
self.register_renamed("unsafe_block", "unsafe_blocks");
|
||||
self.register_renamed("unnecessary_allocation", "unused_allocation");
|
||||
self.register_renamed("missing_doc", "missing_docs");
|
||||
self.register_renamed("unused_extern_crate", "unused_extern_crates");
|
||||
self.register_renamed("unnecessary_qualification", "unused_qualifications");
|
||||
self.register_renamed("unrecognized_lint", "unknown_lints");
|
||||
self.register_renamed("unused_variable", "unused_variables");
|
||||
self.register_renamed("dead_assignment", "unused_assignments");
|
||||
self.register_renamed("unknown_crate_type", "unknown_crate_types");
|
||||
self.register_renamed("variant_size_difference", "variant_size_differences");
|
||||
self.register_renamed("transmute_fat_ptr", "fat_ptr_transmutes");
|
||||
// Insert temporary renamings for a one-time deprecation
|
||||
self.register_renamed("raw_pointer_deriving", "raw_pointer_derive");
|
||||
|
||||
self.register_renamed("unknown_features", "unused_features");
|
||||
@ -595,14 +572,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_view_item(&mut self, i: &ast::ViewItem) {
|
||||
self.with_lint_attrs(&i.attrs[], |cx| {
|
||||
run_lints!(cx, check_view_item, i);
|
||||
cx.visit_ids(|v| v.visit_view_item(i));
|
||||
visit::walk_view_item(cx, i);
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &ast::Pat) {
|
||||
run_lints!(self, check_pat, p);
|
||||
visit::walk_pat(self, p);
|
||||
|
@ -128,7 +128,6 @@ pub trait LintPass {
|
||||
fn check_crate(&mut self, _: &Context, _: &ast::Crate) { }
|
||||
fn check_ident(&mut self, _: &Context, _: Span, _: ast::Ident) { }
|
||||
fn check_mod(&mut self, _: &Context, _: &ast::Mod, _: Span, _: ast::NodeId) { }
|
||||
fn check_view_item(&mut self, _: &Context, _: &ast::ViewItem) { }
|
||||
fn check_foreign_item(&mut self, _: &Context, _: &ast::ForeignItem) { }
|
||||
fn check_item(&mut self, _: &Context, _: &ast::Item) { }
|
||||
fn check_local(&mut self, _: &Context, _: &ast::Local) { }
|
||||
|
@ -40,10 +40,6 @@ pub struct CrateReader<'a> {
|
||||
}
|
||||
|
||||
impl<'a, 'v> visit::Visitor<'v> for CrateReader<'a> {
|
||||
fn visit_view_item(&mut self, a: &ast::ViewItem) {
|
||||
self.process_view_item(a);
|
||||
visit::walk_view_item(self, a);
|
||||
}
|
||||
fn visit_item(&mut self, a: &ast::Item) {
|
||||
self.process_item(a);
|
||||
visit::walk_item(self, a);
|
||||
@ -64,9 +60,8 @@ fn dump_crates(cstore: &CStore) {
|
||||
})
|
||||
}
|
||||
|
||||
fn should_link(i: &ast::ViewItem) -> bool {
|
||||
fn should_link(i: &ast::Item) -> bool {
|
||||
!attr::contains_name(&i.attrs[], "no_link")
|
||||
|
||||
}
|
||||
|
||||
struct CrateInfo {
|
||||
@ -181,29 +176,10 @@ impl<'a> CrateReader<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn process_view_item(&mut self, i: &ast::ViewItem) {
|
||||
if !should_link(i) {
|
||||
return;
|
||||
}
|
||||
|
||||
match self.extract_crate_info(i) {
|
||||
Some(info) => {
|
||||
let (cnum, _, _) = self.resolve_crate(&None,
|
||||
&info.ident[],
|
||||
&info.name[],
|
||||
None,
|
||||
i.span,
|
||||
PathKind::Crate);
|
||||
self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_crate_info(&self, i: &ast::ViewItem) -> Option<CrateInfo> {
|
||||
fn extract_crate_info(&self, i: &ast::Item) -> Option<CrateInfo> {
|
||||
match i.node {
|
||||
ast::ViewItemExternCrate(ident, ref path_opt, id) => {
|
||||
let ident = token::get_ident(ident);
|
||||
ast::ItemExternCrate(ref path_opt) => {
|
||||
let ident = token::get_ident(i.ident);
|
||||
debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
|
||||
ident, path_opt);
|
||||
let name = match *path_opt {
|
||||
@ -218,7 +194,7 @@ impl<'a> CrateReader<'a> {
|
||||
Some(CrateInfo {
|
||||
ident: ident.get().to_string(),
|
||||
name: name,
|
||||
id: id,
|
||||
id: i.id,
|
||||
should_link: should_link(i),
|
||||
})
|
||||
}
|
||||
@ -226,8 +202,26 @@ impl<'a> CrateReader<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn process_item(&self, i: &ast::Item) {
|
||||
fn process_item(&mut self, i: &ast::Item) {
|
||||
match i.node {
|
||||
ast::ItemExternCrate(_) => {
|
||||
if !should_link(i) {
|
||||
return;
|
||||
}
|
||||
|
||||
match self.extract_crate_info(i) {
|
||||
Some(info) => {
|
||||
let (cnum, _, _) = self.resolve_crate(&None,
|
||||
&info.ident[],
|
||||
&info.name[],
|
||||
None,
|
||||
i.span,
|
||||
PathKind::Crate);
|
||||
self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
ast::ItemForeignMod(ref fm) => {
|
||||
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic {
|
||||
return;
|
||||
@ -533,7 +527,7 @@ impl<'a> CrateReader<'a> {
|
||||
|
||||
#[derive(Copy)]
|
||||
pub enum CrateOrString<'a> {
|
||||
Krate(&'a ast::ViewItem),
|
||||
Krate(&'a ast::Item),
|
||||
Str(&'a str)
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ impl MetadataBlob {
|
||||
((slice[2] as u32) << 8) |
|
||||
((slice[3] as u32) << 0)) as uint;
|
||||
if len + 4 <= slice.len() {
|
||||
slice.slice(4, len + 4)
|
||||
&slice[4.. len + 4]
|
||||
} else {
|
||||
&[] // corrupt or old metadata
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user