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:
Brian Anderson 2015-01-24 09:15:42 -08:00
commit 63fcbcf3ce
433 changed files with 7348 additions and 12011 deletions

1
configure vendored
View File

@ -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"

View 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

View File

@ -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

View File

@ -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
################################################################################

View File

@ -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

View File

@ -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>,

View File

@ -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
}

View File

@ -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, }))
}

View File

@ -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)
}

View File

@ -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;
}

View File

@ -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]);
});
}
}

View File

@ -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

View File

@ -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).

View File

@ -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)

View File

@ -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

View File

@ -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

View 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.

View File

@ -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

View File

@ -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);

View 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
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)

View File

@ -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:

View File

@ -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() {

View File

@ -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

View File

@ -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`

View File

@ -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
View 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)

View File

@ -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}")

View 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());

View File

@ -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>

View File

@ -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)
}
}

View 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));
}

View File

@ -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);

View File

@ -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;

View File

@ -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");
}
}

View File

@ -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]

View File

@ -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 {{"));

View File

@ -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);

View File

@ -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 {}");
}
}

View File

@ -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)

View File

@ -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;

View File

@ -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),*])
}

View File

@ -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)

View File

@ -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;

View File

@ -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 {

View File

@ -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]

View File

@ -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]

View File

@ -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 {}");
}

View File

@ -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>() }
}
}

View File

@ -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)
}
}

View File

@ -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),
}
}
}

View File

@ -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

View File

@ -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" }
}

View File

@ -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(())

View File

@ -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)
}
}

View File

@ -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 }

View File

@ -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

View File

@ -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;

View File

@ -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",

View File

@ -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> {

View File

@ -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
}
}

View File

@ -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

View File

@ -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]

View File

@ -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;

View File

@ -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));
}

View File

@ -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)) })
}
}

View File

@ -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();

View File

@ -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());

View File

@ -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\")");
}

View File

@ -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)");
}

View File

@ -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;

View File

@ -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 => {;}
}
}
}

View File

@ -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)
}

View File

@ -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,

View File

@ -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)]

View File

@ -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 _;
}
});

View File

@ -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 {
}
}
}

View File

@ -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);

View File

@ -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 {

View File

@ -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."),
}
}
}

View File

@ -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

View File

@ -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()
}

View File

@ -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}

View File

@ -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))}

View File

@ -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"));
}

View File

@ -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", "", 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;

View File

@ -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.

View File

@ -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'.

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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
}

View File

@ -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 }

View File

@ -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.
//

View File

@ -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));

View File

@ -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);

View File

@ -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) { }

View File

@ -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)
}

View File

@ -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