auto merge of #14187 : alexcrichton/rust/rollup, r=alexcrichton
Closes #14184 (std: Move the owned module from core to std) Closes #14183 (Allow blocks in const expressions) Closes #14176 (Add tests for from_bits.) Closes #14175 (Replaced ~T by Box<T> in manual) Closes #14173 (Implements Default trait for BigInt and BigUint) Closes #14171 (Fix #8391) Closes #14159 (Clean up unicode code in libstd) Closes #14126 (docs: Add a not found page) Closes #14123 (add a line to the example to clarify semantics) Closes #14106 (Pretty printer improvements) Closes #14083 (rustllvm: Add LLVMRustArrayType) Closes #13957 (io: Implement process wait timeouts)
This commit is contained in:
commit
b2b383cab5
|
@ -30,7 +30,7 @@ DOCS := index intro tutorial guide-ffi guide-macros guide-lifetimes \
|
|||
guide-tasks guide-container guide-pointers guide-testing \
|
||||
guide-runtime complement-bugreport complement-cheatsheet \
|
||||
complement-lang-faq complement-project-faq rust rustdoc \
|
||||
guide-unsafe
|
||||
guide-unsafe not_found
|
||||
|
||||
PDF_DOCS := tutorial rust
|
||||
|
||||
|
|
|
@ -8,19 +8,52 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::from_str::FromStr;
|
||||
use std::fmt;
|
||||
|
||||
#[deriving(Clone, Eq)]
|
||||
pub enum mode {
|
||||
mode_compile_fail,
|
||||
mode_run_fail,
|
||||
mode_run_pass,
|
||||
mode_pretty,
|
||||
mode_debug_info_gdb,
|
||||
mode_debug_info_lldb,
|
||||
mode_codegen
|
||||
pub enum Mode {
|
||||
CompileFail,
|
||||
RunFail,
|
||||
RunPass,
|
||||
Pretty,
|
||||
DebugInfoGdb,
|
||||
DebugInfoLldb,
|
||||
Codegen
|
||||
}
|
||||
|
||||
impl FromStr for Mode {
|
||||
fn from_str(s: &str) -> Option<Mode> {
|
||||
match s {
|
||||
"compile-fail" => Some(CompileFail),
|
||||
"run-fail" => Some(RunFail),
|
||||
"run-pass" => Some(RunPass),
|
||||
"pretty" => Some(Pretty),
|
||||
"debuginfo-lldb" => Some(DebugInfoLldb),
|
||||
"debuginfo-gdb" => Some(DebugInfoGdb),
|
||||
"codegen" => Some(Codegen),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Show for Mode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let msg = match *self {
|
||||
CompileFail => "compile-fail",
|
||||
RunFail => "run-fail",
|
||||
RunPass => "run-pass",
|
||||
Pretty => "pretty",
|
||||
DebugInfoGdb => "debuginfo-gdb",
|
||||
DebugInfoLldb => "debuginfo-lldb",
|
||||
Codegen => "codegen",
|
||||
};
|
||||
write!(f.buf, "{}", msg)
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct config {
|
||||
pub struct Config {
|
||||
// The library paths required for running the compiler
|
||||
pub compile_lib_path: ~str,
|
||||
|
||||
|
@ -49,7 +82,7 @@ pub struct config {
|
|||
pub stage_id: ~str,
|
||||
|
||||
// The test mode, compile-fail, run-fail, run-pass
|
||||
pub mode: mode,
|
||||
pub mode: Mode,
|
||||
|
||||
// Run ignored tests
|
||||
pub run_ignored: bool,
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
// we use our own (green) start below; do not link in libnative; issue #13247.
|
||||
#![no_start]
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
#![deny(warnings)]
|
||||
|
||||
extern crate test;
|
||||
|
@ -27,9 +26,10 @@ extern crate rustuv;
|
|||
use std::os;
|
||||
use std::io;
|
||||
use std::io::fs;
|
||||
use std::from_str::FromStr;
|
||||
use getopts::{optopt, optflag, reqopt};
|
||||
use common::{config, mode_run_pass, mode_run_fail, mode_compile_fail, mode_pretty,
|
||||
mode_debug_info_gdb, mode_debug_info_lldb, mode_codegen, mode};
|
||||
use common::Config;
|
||||
use common::{Pretty, DebugInfoGdb, Codegen};
|
||||
use util::logv;
|
||||
|
||||
pub mod procsrv;
|
||||
|
@ -51,7 +51,7 @@ pub fn main() {
|
|||
run_tests(&config);
|
||||
}
|
||||
|
||||
pub fn parse_config(args: Vec<~str> ) -> config {
|
||||
pub fn parse_config(args: Vec<~str> ) -> Config {
|
||||
|
||||
let groups : Vec<getopts::OptGroup> =
|
||||
vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
|
||||
|
@ -112,7 +112,7 @@ pub fn parse_config(args: Vec<~str> ) -> config {
|
|||
Path::new(m.opt_str(nm).unwrap())
|
||||
}
|
||||
|
||||
config {
|
||||
Config {
|
||||
compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
|
||||
run_lib_path: matches.opt_str("run-lib-path").unwrap(),
|
||||
rustc_path: opt_path(matches, "rustc-path"),
|
||||
|
@ -122,7 +122,7 @@ pub fn parse_config(args: Vec<~str> ) -> config {
|
|||
build_base: opt_path(matches, "build-base"),
|
||||
aux_base: opt_path(matches, "aux-base"),
|
||||
stage_id: matches.opt_str("stage-id").unwrap(),
|
||||
mode: str_mode(matches.opt_str("mode").unwrap()),
|
||||
mode: FromStr::from_str(matches.opt_str("mode").unwrap()).expect("invalid mode"),
|
||||
run_ignored: matches.opt_present("ignored"),
|
||||
filter:
|
||||
if !matches.free.is_empty() {
|
||||
|
@ -155,7 +155,7 @@ pub fn parse_config(args: Vec<~str> ) -> config {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn log_config(config: &config) {
|
||||
pub fn log_config(config: &Config) {
|
||||
let c = config;
|
||||
logv(c, format!("configuration:"));
|
||||
logv(c, format!("compile_lib_path: {}", config.compile_lib_path));
|
||||
|
@ -164,7 +164,7 @@ pub fn log_config(config: &config) {
|
|||
logv(c, format!("src_base: {}", config.src_base.display()));
|
||||
logv(c, format!("build_base: {}", config.build_base.display()));
|
||||
logv(c, format!("stage_id: {}", config.stage_id));
|
||||
logv(c, format!("mode: {}", mode_str(config.mode)));
|
||||
logv(c, format!("mode: {}", config.mode));
|
||||
logv(c, format!("run_ignored: {}", config.run_ignored));
|
||||
logv(c, format!("filter: {}", opt_str(&config.filter)));
|
||||
logv(c, format!("runtool: {}", opt_str(&config.runtool)));
|
||||
|
@ -198,35 +198,10 @@ pub fn opt_str2(maybestr: Option<~str>) -> ~str {
|
|||
match maybestr { None => "(none)".to_owned(), Some(s) => { s } }
|
||||
}
|
||||
|
||||
pub fn str_mode(s: ~str) -> mode {
|
||||
match s.as_slice() {
|
||||
"compile-fail" => mode_compile_fail,
|
||||
"run-fail" => mode_run_fail,
|
||||
"run-pass" => mode_run_pass,
|
||||
"pretty" => mode_pretty,
|
||||
"debuginfo-gdb" => mode_debug_info_gdb,
|
||||
"debuginfo-lldb" => mode_debug_info_lldb,
|
||||
"codegen" => mode_codegen,
|
||||
s => fail!("invalid mode: " + s)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mode_str(mode: mode) -> ~str {
|
||||
match mode {
|
||||
mode_compile_fail => "compile-fail".to_owned(),
|
||||
mode_run_fail => "run-fail".to_owned(),
|
||||
mode_run_pass => "run-pass".to_owned(),
|
||||
mode_pretty => "pretty".to_owned(),
|
||||
mode_debug_info_gdb => "debuginfo-gdb".to_owned(),
|
||||
mode_debug_info_lldb => "debuginfo-lldb".to_owned(),
|
||||
mode_codegen => "codegen".to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_tests(config: &config) {
|
||||
pub fn run_tests(config: &Config) {
|
||||
if config.target == "arm-linux-androideabi".to_owned() {
|
||||
match config.mode {
|
||||
mode_debug_info_gdb => {
|
||||
DebugInfoGdb => {
|
||||
println!("arm-linux-androideabi debug-info \
|
||||
test uses tcp 5039 port. please reserve it");
|
||||
}
|
||||
|
@ -255,7 +230,7 @@ pub fn run_tests(config: &config) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn test_opts(config: &config) -> test::TestOpts {
|
||||
pub fn test_opts(config: &Config) -> test::TestOpts {
|
||||
test::TestOpts {
|
||||
filter: config.filter.clone(),
|
||||
run_ignored: config.run_ignored,
|
||||
|
@ -270,7 +245,7 @@ pub fn test_opts(config: &config) -> test::TestOpts {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn make_tests(config: &config) -> Vec<test::TestDescAndFn> {
|
||||
pub fn make_tests(config: &Config) -> Vec<test::TestDescAndFn> {
|
||||
debug!("making tests from {}",
|
||||
config.src_base.display());
|
||||
let mut tests = Vec::new();
|
||||
|
@ -281,7 +256,7 @@ pub fn make_tests(config: &config) -> Vec<test::TestDescAndFn> {
|
|||
if is_test(config, &file) {
|
||||
let t = make_test(config, &file, || {
|
||||
match config.mode {
|
||||
mode_codegen => make_metrics_test_closure(config, &file),
|
||||
Codegen => make_metrics_test_closure(config, &file),
|
||||
_ => make_test_closure(config, &file)
|
||||
}
|
||||
});
|
||||
|
@ -291,11 +266,11 @@ pub fn make_tests(config: &config) -> Vec<test::TestDescAndFn> {
|
|||
tests
|
||||
}
|
||||
|
||||
pub fn is_test(config: &config, testfile: &Path) -> bool {
|
||||
pub fn is_test(config: &Config, testfile: &Path) -> bool {
|
||||
// Pretty-printer does not work with .rc files yet
|
||||
let valid_extensions =
|
||||
match config.mode {
|
||||
mode_pretty => vec!(".rs".to_owned()),
|
||||
Pretty => vec!(".rs".to_owned()),
|
||||
_ => vec!(".rc".to_owned(), ".rs".to_owned())
|
||||
};
|
||||
let invalid_prefixes = vec!(".".to_owned(), "#".to_owned(), "~".to_owned());
|
||||
|
@ -314,7 +289,7 @@ pub fn is_test(config: &config, testfile: &Path) -> bool {
|
|||
return valid;
|
||||
}
|
||||
|
||||
pub fn make_test(config: &config, testfile: &Path, f: || -> test::TestFn)
|
||||
pub fn make_test(config: &Config, testfile: &Path, f: || -> test::TestFn)
|
||||
-> test::TestDescAndFn {
|
||||
test::TestDescAndFn {
|
||||
desc: test::TestDesc {
|
||||
|
@ -326,7 +301,7 @@ pub fn make_test(config: &config, testfile: &Path, f: || -> test::TestFn)
|
|||
}
|
||||
}
|
||||
|
||||
pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
|
||||
pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
|
||||
|
||||
// Try to elide redundant long paths
|
||||
fn shorten(path: &Path) -> ~str {
|
||||
|
@ -336,19 +311,17 @@ pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
|
|||
format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
|
||||
}
|
||||
|
||||
test::DynTestName(format!("[{}] {}",
|
||||
mode_str(config.mode),
|
||||
shorten(testfile)))
|
||||
test::DynTestName(format!("[{}] {}", config.mode, shorten(testfile)))
|
||||
}
|
||||
|
||||
pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
|
||||
pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
|
||||
let config = (*config).clone();
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let testfile = testfile.as_str().unwrap().to_owned();
|
||||
test::DynTestFn(proc() { runtest::run(config, testfile) })
|
||||
}
|
||||
|
||||
pub fn make_metrics_test_closure(config: &config, testfile: &Path) -> test::TestFn {
|
||||
pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
|
||||
let config = (*config).clone();
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let testfile = testfile.as_str().unwrap().to_owned();
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use common::config;
|
||||
use common::Config;
|
||||
use common;
|
||||
use util;
|
||||
|
||||
|
@ -34,6 +34,8 @@ pub struct TestProps {
|
|||
pub check_stdout: bool,
|
||||
// Don't force a --crate-type=dylib flag on the command line
|
||||
pub no_prefer_dynamic: bool,
|
||||
// Don't run --pretty expanded when running pretty printing tests
|
||||
pub no_pretty_expanded: bool,
|
||||
}
|
||||
|
||||
// Load any test directives embedded in the file
|
||||
|
@ -48,6 +50,7 @@ pub fn load_props(testfile: &Path) -> TestProps {
|
|||
let mut force_host = false;
|
||||
let mut check_stdout = false;
|
||||
let mut no_prefer_dynamic = false;
|
||||
let mut no_pretty_expanded = false;
|
||||
iter_header(testfile, |ln| {
|
||||
match parse_error_pattern(ln) {
|
||||
Some(ep) => error_patterns.push(ep),
|
||||
|
@ -78,6 +81,10 @@ pub fn load_props(testfile: &Path) -> TestProps {
|
|||
no_prefer_dynamic = parse_no_prefer_dynamic(ln);
|
||||
}
|
||||
|
||||
if !no_pretty_expanded {
|
||||
no_pretty_expanded = parse_no_pretty_expanded(ln);
|
||||
}
|
||||
|
||||
match parse_aux_build(ln) {
|
||||
Some(ab) => { aux_builds.push(ab); }
|
||||
None => {}
|
||||
|
@ -107,14 +114,15 @@ pub fn load_props(testfile: &Path) -> TestProps {
|
|||
force_host: force_host,
|
||||
check_stdout: check_stdout,
|
||||
no_prefer_dynamic: no_prefer_dynamic,
|
||||
no_pretty_expanded: no_pretty_expanded,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_test_ignored(config: &config, testfile: &Path) -> bool {
|
||||
fn ignore_target(config: &config) -> ~str {
|
||||
pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
|
||||
fn ignore_target(config: &Config) -> ~str {
|
||||
"ignore-".to_owned() + util::get_os(config.target)
|
||||
}
|
||||
fn ignore_stage(config: &config) -> ~str {
|
||||
fn ignore_stage(config: &Config) -> ~str {
|
||||
"ignore-".to_owned() + config.stage_id.split('-').next().unwrap()
|
||||
}
|
||||
|
||||
|
@ -122,7 +130,7 @@ pub fn is_test_ignored(config: &config, testfile: &Path) -> bool {
|
|||
if parse_name_directive(ln, "ignore-test") { false }
|
||||
else if parse_name_directive(ln, ignore_target(config)) { false }
|
||||
else if parse_name_directive(ln, ignore_stage(config)) { false }
|
||||
else if config.mode == common::mode_pretty &&
|
||||
else if config.mode == common::Pretty &&
|
||||
parse_name_directive(ln, "ignore-pretty") { false }
|
||||
else if config.target != config.host &&
|
||||
parse_name_directive(ln, "ignore-cross-compile") { false }
|
||||
|
@ -180,6 +188,10 @@ fn parse_no_prefer_dynamic(line: &str) -> bool {
|
|||
parse_name_directive(line, "no-prefer-dynamic")
|
||||
}
|
||||
|
||||
fn parse_no_pretty_expanded(line: &str) -> bool {
|
||||
parse_name_directive(line, "no-pretty-expanded")
|
||||
}
|
||||
|
||||
fn parse_exec_env(line: &str) -> Option<(~str, ~str)> {
|
||||
parse_name_value_directive(line, "exec-env".to_owned()).map(|nv| {
|
||||
// nv is either FOO or FOO=BAR
|
||||
|
|
|
@ -68,7 +68,7 @@ pub fn run(lib_path: &str,
|
|||
input: Option<~str>) -> Option<Result> {
|
||||
|
||||
let env = env.clone().append(target_env(lib_path, prog).as_slice());
|
||||
let mut opt_process = Process::configure(ProcessConfig {
|
||||
let opt_process = Process::configure(ProcessConfig {
|
||||
program: prog,
|
||||
args: args,
|
||||
env: Some(env.as_slice()),
|
||||
|
@ -76,11 +76,12 @@ pub fn run(lib_path: &str,
|
|||
});
|
||||
|
||||
match opt_process {
|
||||
Ok(ref mut process) => {
|
||||
Ok(mut process) => {
|
||||
for input in input.iter() {
|
||||
process.stdin.get_mut_ref().write(input.as_bytes()).unwrap();
|
||||
}
|
||||
let ProcessOutput { status, output, error } = process.wait_with_output();
|
||||
let ProcessOutput { status, output, error } =
|
||||
process.wait_with_output().unwrap();
|
||||
|
||||
Some(Result {
|
||||
status: status,
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use common::{config, mode_compile_fail, mode_pretty, mode_run_fail, mode_run_pass};
|
||||
use common::Config;
|
||||
use common::{CompileFail, Pretty, RunFail, RunPass, DebugInfoGdb, DebugInfoLldb};
|
||||
use errors;
|
||||
use header::TestProps;
|
||||
use header;
|
||||
|
@ -30,7 +31,7 @@ use std::strbuf::StrBuf;
|
|||
use std::task;
|
||||
use test::MetricMap;
|
||||
|
||||
pub fn run(config: config, testfile: ~str) {
|
||||
pub fn run(config: Config, testfile: ~str) {
|
||||
|
||||
match config.target.as_slice() {
|
||||
|
||||
|
@ -47,7 +48,7 @@ pub fn run(config: config, testfile: ~str) {
|
|||
run_metrics(config, testfile, &mut _mm);
|
||||
}
|
||||
|
||||
pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) {
|
||||
pub fn run_metrics(config: Config, testfile: ~str, mm: &mut MetricMap) {
|
||||
if config.verbose {
|
||||
// We're going to be dumping a lot of info. Start on a new line.
|
||||
print!("\n\n");
|
||||
|
@ -57,17 +58,17 @@ pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) {
|
|||
let props = header::load_props(&testfile);
|
||||
debug!("loaded props");
|
||||
match config.mode {
|
||||
mode_compile_fail => run_cfail_test(&config, &props, &testfile),
|
||||
mode_run_fail => run_rfail_test(&config, &props, &testfile),
|
||||
mode_run_pass => run_rpass_test(&config, &props, &testfile),
|
||||
mode_pretty => run_pretty_test(&config, &props, &testfile),
|
||||
mode_debug_info_gdb => run_debuginfo_gdb_test(&config, &props, &testfile),
|
||||
mode_debug_info_lldb => run_debuginfo_lldb_test(&config, &props, &testfile),
|
||||
mode_codegen => run_codegen_test(&config, &props, &testfile, mm)
|
||||
CompileFail => run_cfail_test(&config, &props, &testfile),
|
||||
RunFail => run_rfail_test(&config, &props, &testfile),
|
||||
RunPass => run_rpass_test(&config, &props, &testfile),
|
||||
Pretty => run_pretty_test(&config, &props, &testfile),
|
||||
DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile),
|
||||
DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile),
|
||||
Codegen => run_codegen_test(&config, &props, &testfile, mm),
|
||||
}
|
||||
}
|
||||
|
||||
fn run_cfail_test(config: &config, props: &TestProps, testfile: &Path) {
|
||||
fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
let proc_res = compile_test(config, props, testfile);
|
||||
|
||||
if proc_res.status.success() {
|
||||
|
@ -88,7 +89,7 @@ fn run_cfail_test(config: &config, props: &TestProps, testfile: &Path) {
|
|||
check_no_compiler_crash(&proc_res);
|
||||
}
|
||||
|
||||
fn run_rfail_test(config: &config, props: &TestProps, testfile: &Path) {
|
||||
fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
let proc_res = if !config.jit {
|
||||
let proc_res = compile_test(config, props, testfile);
|
||||
|
||||
|
@ -121,7 +122,7 @@ fn check_correct_failure_status(proc_res: &ProcRes) {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_rpass_test(config: &config, props: &TestProps, testfile: &Path) {
|
||||
fn run_rpass_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
if !config.jit {
|
||||
let mut proc_res = compile_test(config, props, testfile);
|
||||
|
||||
|
@ -141,7 +142,7 @@ fn run_rpass_test(config: &config, props: &TestProps, testfile: &Path) {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) {
|
||||
fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
if props.pp_exact.is_some() {
|
||||
logv(config, "testing for exact pretty-printing".to_owned());
|
||||
} else { logv(config, "testing for converging pretty-printing".to_owned()); }
|
||||
|
@ -156,9 +157,7 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) {
|
|||
let mut round = 0;
|
||||
while round < rounds {
|
||||
logv(config, format!("pretty-printing round {}", round));
|
||||
let proc_res = print_source(config,
|
||||
testfile,
|
||||
(*srcs.get(round)).clone());
|
||||
let proc_res = print_source(config, props, testfile, (*srcs.get(round)).clone(), "normal");
|
||||
|
||||
if !proc_res.status.success() {
|
||||
fatal_ProcRes(format!("pretty-printing failed in round {}", round),
|
||||
|
@ -195,18 +194,43 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) {
|
|||
if !proc_res.status.success() {
|
||||
fatal_ProcRes("pretty-printed source does not typecheck".to_owned(), &proc_res);
|
||||
}
|
||||
if props.no_pretty_expanded { return }
|
||||
|
||||
// additionally, run `--pretty expanded` and try to build it.
|
||||
let proc_res = print_source(config, props, testfile, (*srcs.get(round)).clone(), "expanded");
|
||||
if !proc_res.status.success() {
|
||||
fatal_ProcRes(format!("pretty-printing (expanded) failed"), &proc_res);
|
||||
}
|
||||
|
||||
let ProcRes{ stdout: expanded_src, .. } = proc_res;
|
||||
let proc_res = typecheck_source(config, props, testfile, expanded_src);
|
||||
if !proc_res.status.success() {
|
||||
fatal_ProcRes(format!("pretty-printed source (expanded) does not typecheck"), &proc_res);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
fn print_source(config: &config, testfile: &Path, src: ~str) -> ProcRes {
|
||||
compose_and_run(config, testfile, make_pp_args(config, testfile),
|
||||
Vec::new(), config.compile_lib_path, Some(src))
|
||||
fn print_source(config: &Config,
|
||||
props: &TestProps,
|
||||
testfile: &Path,
|
||||
src: ~str,
|
||||
pretty_type: &str) -> ProcRes {
|
||||
compose_and_run(config, testfile,
|
||||
make_pp_args(config, props, testfile, pretty_type.to_owned()),
|
||||
props.exec_env.clone(), config.compile_lib_path, Some(src))
|
||||
}
|
||||
|
||||
fn make_pp_args(config: &config, _testfile: &Path) -> ProcArgs {
|
||||
let args = vec!("-".to_owned(), "--pretty".to_owned(), "normal".to_owned(),
|
||||
"--target=".to_owned() + config.target);
|
||||
fn make_pp_args(config: &Config,
|
||||
props: &TestProps,
|
||||
testfile: &Path,
|
||||
pretty_type: ~str) -> ProcArgs {
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut args = vec!("-".to_owned(), "--pretty".to_owned(), pretty_type,
|
||||
"--target=".to_owned() + config.target,
|
||||
"-L".to_owned(), aux_dir.as_str().unwrap().to_owned());
|
||||
args.push_all_move(split_maybe_args(&config.target_rustcflags));
|
||||
args.push_all_move(split_maybe_args(&props.compile_flags));
|
||||
return ProcArgs {prog: config.rustc_path.as_str().unwrap().to_owned(), args: args};
|
||||
}
|
||||
|
||||
|
@ -228,13 +252,13 @@ actual:\n\
|
|||
}
|
||||
}
|
||||
|
||||
fn typecheck_source(config: &config, props: &TestProps,
|
||||
fn typecheck_source(config: &Config, props: &TestProps,
|
||||
testfile: &Path, src: ~str) -> ProcRes {
|
||||
let args = make_typecheck_args(config, props, testfile);
|
||||
compose_and_run_compiler(config, props, testfile, args, Some(src))
|
||||
}
|
||||
|
||||
fn make_typecheck_args(config: &config, props: &TestProps, testfile: &Path) -> ProcArgs {
|
||||
fn make_typecheck_args(config: &Config, props: &TestProps, testfile: &Path) -> ProcArgs {
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
let target = if props.force_host {
|
||||
config.host.as_slice()
|
||||
|
@ -255,8 +279,8 @@ actual:\n\
|
|||
}
|
||||
}
|
||||
|
||||
fn run_debuginfo_gdb_test(config: &config, props: &TestProps, testfile: &Path) {
|
||||
let mut config = config {
|
||||
fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
let mut config = Config {
|
||||
target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
|
||||
host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
|
||||
.. config.clone()
|
||||
|
@ -403,14 +427,14 @@ fn run_debuginfo_gdb_test(config: &config, props: &TestProps, testfile: &Path) {
|
|||
check_debugger_output(&debugger_run_result, check_lines.as_slice());
|
||||
}
|
||||
|
||||
fn run_debuginfo_lldb_test(config: &config, props: &TestProps, testfile: &Path) {
|
||||
fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
use std::io::process::{Process, ProcessConfig, ProcessOutput};
|
||||
|
||||
if config.lldb_python_dir.is_none() {
|
||||
fatal("Can't run LLDB test because LLDB's python path is not set.".to_owned());
|
||||
}
|
||||
|
||||
let mut config = config {
|
||||
let mut config = Config {
|
||||
target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
|
||||
host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
|
||||
.. config.clone()
|
||||
|
@ -465,7 +489,7 @@ fn run_debuginfo_lldb_test(config: &config, props: &TestProps, testfile: &Path)
|
|||
|
||||
check_debugger_output(&debugger_run_result, check_lines.as_slice());
|
||||
|
||||
fn run_lldb(config: &config, test_executable: &Path, debugger_script: &Path) -> ProcRes {
|
||||
fn run_lldb(config: &Config, test_executable: &Path, debugger_script: &Path) -> ProcRes {
|
||||
// Prepare the lldb_batchmode which executes the debugger script
|
||||
let lldb_batchmode_script = "./src/etc/lldb_batchmode.py".to_owned();
|
||||
let test_executable_str = test_executable.as_str().unwrap().to_owned();
|
||||
|
@ -478,7 +502,7 @@ fn run_debuginfo_lldb_test(config: &config, props: &TestProps, testfile: &Path)
|
|||
let args = &[lldb_batchmode_script, test_executable_str, debugger_script_str];
|
||||
let env = &[("PYTHONPATH".to_owned(), config.lldb_python_dir.clone().unwrap())];
|
||||
|
||||
let mut opt_process = Process::configure(ProcessConfig {
|
||||
let opt_process = Process::configure(ProcessConfig {
|
||||
program: "python",
|
||||
args: args,
|
||||
env: Some(env),
|
||||
|
@ -486,8 +510,9 @@ fn run_debuginfo_lldb_test(config: &config, props: &TestProps, testfile: &Path)
|
|||
});
|
||||
|
||||
let (status, out, err) = match opt_process {
|
||||
Ok(ref mut process) => {
|
||||
let ProcessOutput { status, output, error } = process.wait_with_output();
|
||||
Ok(process) => {
|
||||
let ProcessOutput { status, output, error } =
|
||||
process.wait_with_output().unwrap();
|
||||
|
||||
(status,
|
||||
str::from_utf8(output.as_slice()).unwrap().to_owned(),
|
||||
|
@ -834,16 +859,16 @@ struct ProcArgs {prog: ~str, args: Vec<~str> }
|
|||
|
||||
struct ProcRes {status: ProcessExit, stdout: ~str, stderr: ~str, cmdline: ~str}
|
||||
|
||||
fn compile_test(config: &config, props: &TestProps,
|
||||
fn compile_test(config: &Config, props: &TestProps,
|
||||
testfile: &Path) -> ProcRes {
|
||||
compile_test_(config, props, testfile, [])
|
||||
}
|
||||
|
||||
fn jit_test(config: &config, props: &TestProps, testfile: &Path) -> ProcRes {
|
||||
fn jit_test(config: &Config, props: &TestProps, testfile: &Path) -> ProcRes {
|
||||
compile_test_(config, props, testfile, ["--jit".to_owned()])
|
||||
}
|
||||
|
||||
fn compile_test_(config: &config, props: &TestProps,
|
||||
fn compile_test_(config: &Config, props: &TestProps,
|
||||
testfile: &Path, extra_args: &[~str]) -> ProcRes {
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
|
@ -855,7 +880,7 @@ fn compile_test_(config: &config, props: &TestProps,
|
|||
compose_and_run_compiler(config, props, testfile, args, None)
|
||||
}
|
||||
|
||||
fn exec_compiled_test(config: &config, props: &TestProps,
|
||||
fn exec_compiled_test(config: &Config, props: &TestProps,
|
||||
testfile: &Path) -> ProcRes {
|
||||
|
||||
let env = props.exec_env.clone();
|
||||
|
@ -876,7 +901,7 @@ fn exec_compiled_test(config: &config, props: &TestProps,
|
|||
}
|
||||
|
||||
fn compose_and_run_compiler(
|
||||
config: &config,
|
||||
config: &Config,
|
||||
props: &TestProps,
|
||||
testfile: &Path,
|
||||
args: ProcArgs,
|
||||
|
@ -934,7 +959,7 @@ fn ensure_dir(path: &Path) {
|
|||
fs::mkdir(path, io::UserRWX).unwrap();
|
||||
}
|
||||
|
||||
fn compose_and_run(config: &config, testfile: &Path,
|
||||
fn compose_and_run(config: &Config, testfile: &Path,
|
||||
ProcArgs{ args, prog }: ProcArgs,
|
||||
procenv: Vec<(~str, ~str)> ,
|
||||
lib_path: &str,
|
||||
|
@ -948,10 +973,10 @@ enum TargetLocation {
|
|||
ThisDirectory(Path),
|
||||
}
|
||||
|
||||
fn make_compile_args(config: &config,
|
||||
fn make_compile_args(config: &Config,
|
||||
props: &TestProps,
|
||||
extras: Vec<~str> ,
|
||||
xform: |&config, &Path| -> TargetLocation,
|
||||
xform: |&Config, &Path| -> TargetLocation,
|
||||
testfile: &Path)
|
||||
-> ProcArgs {
|
||||
let xform_file = xform(config, testfile);
|
||||
|
@ -983,14 +1008,14 @@ fn make_compile_args(config: &config,
|
|||
return ProcArgs {prog: config.rustc_path.as_str().unwrap().to_owned(), args: args};
|
||||
}
|
||||
|
||||
fn make_lib_name(config: &config, auxfile: &Path, testfile: &Path) -> Path {
|
||||
fn make_lib_name(config: &Config, auxfile: &Path, testfile: &Path) -> Path {
|
||||
// what we return here is not particularly important, as it
|
||||
// happens; rustc ignores everything except for the directory.
|
||||
let auxname = output_testname(auxfile);
|
||||
aux_output_dir_name(config, testfile).join(&auxname)
|
||||
}
|
||||
|
||||
fn make_exe_name(config: &config, testfile: &Path) -> Path {
|
||||
fn make_exe_name(config: &Config, testfile: &Path) -> Path {
|
||||
let mut f = output_base_name(config, testfile);
|
||||
if !os::consts::EXE_SUFFIX.is_empty() {
|
||||
match f.filename().map(|s| Vec::from_slice(s).append(os::consts::EXE_SUFFIX.as_bytes())) {
|
||||
|
@ -1001,7 +1026,7 @@ fn make_exe_name(config: &config, testfile: &Path) -> Path {
|
|||
f
|
||||
}
|
||||
|
||||
fn make_run_args(config: &config, props: &TestProps, testfile: &Path) ->
|
||||
fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) ->
|
||||
ProcArgs {
|
||||
// If we've got another tool to run under (valgrind),
|
||||
// then split apart its command
|
||||
|
@ -1029,7 +1054,7 @@ fn split_maybe_args(argstr: &Option<~str>) -> Vec<~str> {
|
|||
}
|
||||
}
|
||||
|
||||
fn program_output(config: &config, testfile: &Path, lib_path: &str, prog: ~str,
|
||||
fn program_output(config: &Config, testfile: &Path, lib_path: &str, prog: ~str,
|
||||
args: Vec<~str> , env: Vec<(~str, ~str)> ,
|
||||
input: Option<~str>) -> ProcRes {
|
||||
let cmdline =
|
||||
|
@ -1069,23 +1094,23 @@ fn lib_path_cmd_prefix(path: &str) -> ~str {
|
|||
format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
|
||||
}
|
||||
|
||||
fn dump_output(config: &config, testfile: &Path, out: &str, err: &str) {
|
||||
fn dump_output(config: &Config, testfile: &Path, out: &str, err: &str) {
|
||||
dump_output_file(config, testfile, out, "out");
|
||||
dump_output_file(config, testfile, err, "err");
|
||||
maybe_dump_to_stdout(config, out, err);
|
||||
}
|
||||
|
||||
fn dump_output_file(config: &config, testfile: &Path,
|
||||
fn dump_output_file(config: &Config, testfile: &Path,
|
||||
out: &str, extension: &str) {
|
||||
let outfile = make_out_name(config, testfile, extension);
|
||||
File::create(&outfile).write(out.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
fn make_out_name(config: &config, testfile: &Path, extension: &str) -> Path {
|
||||
fn make_out_name(config: &Config, testfile: &Path, extension: &str) -> Path {
|
||||
output_base_name(config, testfile).with_extension(extension)
|
||||
}
|
||||
|
||||
fn aux_output_dir_name(config: &config, testfile: &Path) -> Path {
|
||||
fn aux_output_dir_name(config: &Config, testfile: &Path) -> Path {
|
||||
let mut f = output_base_name(config, testfile);
|
||||
match f.filename().map(|s| Vec::from_slice(s).append(bytes!(".libaux"))) {
|
||||
Some(v) => f.set_filename(v),
|
||||
|
@ -1098,13 +1123,13 @@ fn output_testname(testfile: &Path) -> Path {
|
|||
Path::new(testfile.filestem().unwrap())
|
||||
}
|
||||
|
||||
fn output_base_name(config: &config, testfile: &Path) -> Path {
|
||||
fn output_base_name(config: &Config, testfile: &Path) -> Path {
|
||||
config.build_base
|
||||
.join(&output_testname(testfile))
|
||||
.with_extension(config.stage_id.as_slice())
|
||||
}
|
||||
|
||||
fn maybe_dump_to_stdout(config: &config, out: &str, err: &str) {
|
||||
fn maybe_dump_to_stdout(config: &Config, out: &str, err: &str) {
|
||||
if config.verbose {
|
||||
println!("------{}------------------------------", "stdout");
|
||||
println!("{}", out);
|
||||
|
@ -1137,7 +1162,7 @@ stderr:\n\
|
|||
fail!();
|
||||
}
|
||||
|
||||
fn _arm_exec_compiled_test(config: &config, props: &TestProps,
|
||||
fn _arm_exec_compiled_test(config: &Config, props: &TestProps,
|
||||
testfile: &Path, env: Vec<(~str, ~str)> ) -> ProcRes {
|
||||
|
||||
let args = make_run_args(config, props, testfile);
|
||||
|
@ -1237,7 +1262,7 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps,
|
|||
}
|
||||
}
|
||||
|
||||
fn _arm_push_aux_shared_library(config: &config, testfile: &Path) {
|
||||
fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) {
|
||||
let tdir = aux_output_dir_name(config, testfile);
|
||||
|
||||
let dirs = fs::readdir(&tdir).unwrap();
|
||||
|
@ -1260,7 +1285,7 @@ fn _arm_push_aux_shared_library(config: &config, testfile: &Path) {
|
|||
|
||||
// codegen tests (vs. clang)
|
||||
|
||||
fn make_o_name(config: &config, testfile: &Path) -> Path {
|
||||
fn make_o_name(config: &Config, testfile: &Path) -> Path {
|
||||
output_base_name(config, testfile).with_extension("o")
|
||||
}
|
||||
|
||||
|
@ -1273,7 +1298,7 @@ fn append_suffix_to_stem(p: &Path, suffix: &str) -> Path {
|
|||
}
|
||||
}
|
||||
|
||||
fn compile_test_and_save_bitcode(config: &config, props: &TestProps,
|
||||
fn compile_test_and_save_bitcode(config: &Config, props: &TestProps,
|
||||
testfile: &Path) -> ProcRes {
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
|
@ -1287,7 +1312,7 @@ fn compile_test_and_save_bitcode(config: &config, props: &TestProps,
|
|||
compose_and_run_compiler(config, props, testfile, args, None)
|
||||
}
|
||||
|
||||
fn compile_cc_with_clang_and_save_bitcode(config: &config, _props: &TestProps,
|
||||
fn compile_cc_with_clang_and_save_bitcode(config: &Config, _props: &TestProps,
|
||||
testfile: &Path) -> ProcRes {
|
||||
let bitcodefile = output_base_name(config, testfile).with_extension("bc");
|
||||
let bitcodefile = append_suffix_to_stem(&bitcodefile, "clang");
|
||||
|
@ -1303,7 +1328,7 @@ fn compile_cc_with_clang_and_save_bitcode(config: &config, _props: &TestProps,
|
|||
compose_and_run(config, testfile, proc_args, Vec::new(), "", None)
|
||||
}
|
||||
|
||||
fn extract_function_from_bitcode(config: &config, _props: &TestProps,
|
||||
fn extract_function_from_bitcode(config: &Config, _props: &TestProps,
|
||||
fname: &str, testfile: &Path,
|
||||
suffix: &str) -> ProcRes {
|
||||
let bitcodefile = output_base_name(config, testfile).with_extension("bc");
|
||||
|
@ -1320,7 +1345,7 @@ fn extract_function_from_bitcode(config: &config, _props: &TestProps,
|
|||
compose_and_run(config, testfile, proc_args, Vec::new(), "", None)
|
||||
}
|
||||
|
||||
fn disassemble_extract(config: &config, _props: &TestProps,
|
||||
fn disassemble_extract(config: &Config, _props: &TestProps,
|
||||
testfile: &Path, suffix: &str) -> ProcRes {
|
||||
let bitcodefile = output_base_name(config, testfile).with_extension("bc");
|
||||
let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix);
|
||||
|
@ -1344,7 +1369,7 @@ fn count_extracted_lines(p: &Path) -> uint {
|
|||
}
|
||||
|
||||
|
||||
fn run_codegen_test(config: &config, props: &TestProps,
|
||||
fn run_codegen_test(config: &Config, props: &TestProps,
|
||||
testfile: &Path, mm: &mut MetricMap) {
|
||||
|
||||
if config.llvm_bin_path.is_none() {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use common::config;
|
||||
use common::Config;
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
use std::os::getenv;
|
||||
|
@ -51,7 +51,7 @@ pub fn lib_path_env_var() -> ~str { "PATH".to_owned() }
|
|||
#[cfg(target_os = "win32")]
|
||||
pub fn path_div() -> ~str { ";".to_owned() }
|
||||
|
||||
pub fn logv(config: &config, s: ~str) {
|
||||
pub fn logv(config: &Config, s: ~str) {
|
||||
debug!("{}", s);
|
||||
if config.verbose { println!("{}", s); }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
% Not Found
|
||||
|
||||
<!-- Completely hide the TOC and the section numbers -->
|
||||
<style type="text/css">
|
||||
#TOC { display: none; }
|
||||
.header-section-number { display: none; }
|
||||
li {list-style-type: none; }
|
||||
</style>
|
||||
|
||||
Looks like you've taken a wrong turn.
|
||||
|
||||
Some things that might be helpful to you though:
|
||||
|
||||
## Reference
|
||||
* [The Rust official site](http://rust-lang.org)
|
||||
* [The Rust reference manual](http://static.rust-lang.org/doc/master/rust.html) (* [PDF](http://static.rust-lang.org/doc/master/rust.pdf))
|
||||
|
||||
## Docs
|
||||
* [The standard library (stable)](http://doc.rust-lang.org/doc/0.10/std/index.html)
|
||||
* [The standard library (master)](http://doc.rust-lang.org/doc/master/std/index.html)
|
|
@ -2648,9 +2648,9 @@ before the expression they apply to.
|
|||
: Logical negation. On the boolean type, this flips between `true` and
|
||||
`false`. On integer types, this inverts the individual bits in the
|
||||
two's complement representation of the value.
|
||||
* `~`
|
||||
* `box`
|
||||
: [Boxing](#pointer-types) operators. Allocate a box to hold the value they are applied to,
|
||||
and store the value in it. `~` creates an owned box.
|
||||
and store the value in it. `box` creates an owned box.
|
||||
* `&`
|
||||
: Borrow operator. Returns a reference, pointing to its operand.
|
||||
The operand of a borrow is statically proven to outlive the resulting pointer.
|
||||
|
@ -3156,7 +3156,7 @@ fn main() {
|
|||
~~~~
|
||||
|
||||
Patterns can also dereference pointers by using the `&`,
|
||||
`~` or `@` symbols, as appropriate. For example, these two matches
|
||||
`box` or `@` symbols, as appropriate. For example, these two matches
|
||||
on `x: &int` are equivalent:
|
||||
|
||||
~~~~
|
||||
|
@ -3438,11 +3438,11 @@ All pointers in Rust are explicit first-class values.
|
|||
They can be copied, stored into data structures, and returned from functions.
|
||||
There are four varieties of pointer in Rust:
|
||||
|
||||
* Owning pointers (`~`)
|
||||
* Owning pointers (`Box`)
|
||||
: These point to owned heap allocations (or "boxes") in the shared, inter-task heap.
|
||||
Each owned box has a single owning pointer; pointer and pointee retain a 1:1 relationship at all times.
|
||||
Owning pointers are written `~content`,
|
||||
for example `~int` means an owning pointer to an owned box containing an integer.
|
||||
Owning pointers are written `Box<content>`,
|
||||
for example `Box<int>` means an owning pointer to an owned box containing an integer.
|
||||
Copying an owned box is a "deep" operation:
|
||||
it involves allocating a new owned box and copying the contents of the old box into the new box.
|
||||
Releasing an owning pointer immediately releases its corresponding owned box.
|
||||
|
@ -3562,8 +3562,8 @@ Whereas most calls to trait methods are "early bound" (statically resolved) to s
|
|||
a call to a method on an object type is only resolved to a vtable entry at compile time.
|
||||
The actual implementation for each vtable entry can vary on an object-by-object basis.
|
||||
|
||||
Given a pointer-typed expression `E` of type `&T` or `~T`, where `T` implements trait `R`,
|
||||
casting `E` to the corresponding pointer type `&R` or `~R` results in a value of the _object type_ `R`.
|
||||
Given a pointer-typed expression `E` of type `&T` or `Box<T>`, where `T` implements trait `R`,
|
||||
casting `E` to the corresponding pointer type `&R` or `Box<R>` results in a value of the _object type_ `R`.
|
||||
This result is represented as a pair of pointers:
|
||||
the vtable pointer for the `T` implementation of `R`, and the pointer value of `E`.
|
||||
|
||||
|
@ -3761,7 +3761,7 @@ Local variables are immutable unless declared otherwise like: `let mut x = ...`.
|
|||
|
||||
Function parameters are immutable unless declared with `mut`. The
|
||||
`mut` keyword applies only to the following parameter (so `|mut x, y|`
|
||||
and `fn f(mut x: ~int, y: ~int)` declare one mutable variable `x` and
|
||||
and `fn f(mut x: Box<int>, y: Box<int>)` declare one mutable variable `x` and
|
||||
one immutable variable `y`).
|
||||
|
||||
Methods that take either `self` or `~self` can optionally place them in a
|
||||
|
|
|
@ -455,7 +455,7 @@ against each pattern in order until one matches. The matching pattern
|
|||
executes its corresponding arm.
|
||||
|
||||
~~~~
|
||||
# let my_number = 1;
|
||||
let my_number = 1;
|
||||
match my_number {
|
||||
0 => println!("zero"),
|
||||
1 | 2 => println!("one or two"),
|
||||
|
|
|
@ -169,7 +169,7 @@ fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
|
|||
else if hi < c { Less }
|
||||
else { Greater }
|
||||
}) != None
|
||||
}\n\n
|
||||
}\n
|
||||
""");
|
||||
|
||||
def emit_property_module(f, mod, tbl):
|
||||
|
@ -193,11 +193,11 @@ def emit_property_module(f, mod, tbl):
|
|||
f.write(" pub fn %s(c: char) -> bool {\n" % cat)
|
||||
f.write(" super::bsearch_range_table(c, %s_table)\n" % cat)
|
||||
f.write(" }\n\n")
|
||||
f.write("}\n")
|
||||
f.write("}\n\n")
|
||||
|
||||
|
||||
def emit_conversions_module(f, lowerupper, upperlower):
|
||||
f.write("pub mod conversions {\n")
|
||||
f.write("pub mod conversions {")
|
||||
f.write("""
|
||||
use cmp::{Equal, Less, Greater};
|
||||
use slice::ImmutableVector;
|
||||
|
@ -225,6 +225,7 @@ def emit_conversions_module(f, lowerupper, upperlower):
|
|||
else { Greater }
|
||||
})
|
||||
}
|
||||
|
||||
""");
|
||||
emit_caseconversion_table(f, "LuLl", upperlower)
|
||||
emit_caseconversion_table(f, "LlLu", lowerupper)
|
||||
|
@ -255,13 +256,13 @@ def format_table_content(f, content, indent):
|
|||
line = " "*indent + chunk
|
||||
f.write(line)
|
||||
|
||||
def emit_decomp_module(f, canon, compat, combine):
|
||||
def emit_core_norm_module(f, canon, compat):
|
||||
canon_keys = canon.keys()
|
||||
canon_keys.sort()
|
||||
|
||||
compat_keys = compat.keys()
|
||||
compat_keys.sort()
|
||||
f.write("pub mod decompose {\n");
|
||||
f.write("pub mod normalization {\n");
|
||||
f.write(" use option::Option;\n");
|
||||
f.write(" use option::{Some, None};\n");
|
||||
f.write(" use slice::ImmutableVector;\n");
|
||||
|
@ -279,23 +280,6 @@ def emit_decomp_module(f, canon, compat, combine):
|
|||
}
|
||||
None => None
|
||||
}
|
||||
}\n
|
||||
""")
|
||||
|
||||
f.write("""
|
||||
fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 {
|
||||
use cmp::{Equal, Less, Greater};
|
||||
match r.bsearch(|&(lo, hi, _)| {
|
||||
if lo <= c && c <= hi { Equal }
|
||||
else if hi < c { Less }
|
||||
else { Greater }
|
||||
}) {
|
||||
Some(idx) => {
|
||||
let (_, _, result) = r[idx];
|
||||
result
|
||||
}
|
||||
None => 0
|
||||
}
|
||||
}\n\n
|
||||
""")
|
||||
|
||||
|
@ -337,28 +321,24 @@ def emit_decomp_module(f, canon, compat, combine):
|
|||
format_table_content(f, data, 8)
|
||||
f.write("\n ];\n\n")
|
||||
|
||||
f.write(" static combining_class_table : &'static [(char, char, u8)] = &[\n")
|
||||
ix = 0
|
||||
for pair in combine:
|
||||
f.write(ch_prefix(ix))
|
||||
f.write("(%s, %s, %s)" % (escape_char(pair[0]), escape_char(pair[1]), pair[2]))
|
||||
ix += 1
|
||||
f.write("\n ];\n")
|
||||
|
||||
f.write(" pub fn canonical(c: char, i: |char|) "
|
||||
+ "{ d(c, i, false); }\n\n")
|
||||
f.write(" pub fn compatibility(c: char, i: |char|) "
|
||||
+"{ d(c, i, true); }\n\n")
|
||||
f.write(" pub fn canonical_combining_class(c: char) -> u8 {\n"
|
||||
+ " bsearch_range_value_table(c, combining_class_table)\n"
|
||||
+ " }\n\n")
|
||||
f.write(" fn d(c: char, i: |char|, k: bool) {\n")
|
||||
f.write(" use iter::Iterator;\n");
|
||||
|
||||
f.write(" if c <= '\\x7f' { i(c); return; }\n")
|
||||
|
||||
# First check the canonical decompositions
|
||||
f.write("""
|
||||
pub fn decompose_canonical(c: char, i: |char|) { d(c, i, false); }
|
||||
|
||||
pub fn decompose_compatible(c: char, i: |char|) { d(c, i, true); }
|
||||
|
||||
fn d(c: char, i: |char|, k: bool) {
|
||||
use iter::Iterator;
|
||||
|
||||
// 7-bit ASCII never decomposes
|
||||
if c <= '\\x7f' { i(c); return; }
|
||||
|
||||
// Perform decomposition for Hangul
|
||||
if (c as u32) >= S_BASE && (c as u32) < (S_BASE + S_COUNT) {
|
||||
decompose_hangul(c, i);
|
||||
return;
|
||||
}
|
||||
|
||||
// First check the canonical decompositions
|
||||
match bsearch_table(c, canonical_table) {
|
||||
Some(canon) => {
|
||||
for x in canon.iter() {
|
||||
|
@ -367,13 +347,12 @@ def emit_decomp_module(f, canon, compat, combine):
|
|||
return;
|
||||
}
|
||||
None => ()
|
||||
}\n\n""")
|
||||
}
|
||||
|
||||
# Bottom out if we're not doing compat.
|
||||
f.write(" if !k { i(c); return; }\n")
|
||||
// Bottom out if we're not doing compat.
|
||||
if !k { i(c); return; }
|
||||
|
||||
# Then check the compatibility decompositions
|
||||
f.write("""
|
||||
// Then check the compatibility decompositions
|
||||
match bsearch_table(c, compatibility_table) {
|
||||
Some(compat) => {
|
||||
for x in compat.iter() {
|
||||
|
@ -382,24 +361,83 @@ def emit_decomp_module(f, canon, compat, combine):
|
|||
return;
|
||||
}
|
||||
None => ()
|
||||
}\n\n""")
|
||||
}
|
||||
|
||||
# Finally bottom out.
|
||||
f.write(" i(c);\n")
|
||||
// Finally bottom out.
|
||||
i(c);
|
||||
}
|
||||
|
||||
// Constants from Unicode 6.2.0 Section 3.12 Conjoining Jamo Behavior
|
||||
static S_BASE: u32 = 0xAC00;
|
||||
static L_BASE: u32 = 0x1100;
|
||||
static V_BASE: u32 = 0x1161;
|
||||
static T_BASE: u32 = 0x11A7;
|
||||
static L_COUNT: u32 = 19;
|
||||
static V_COUNT: u32 = 21;
|
||||
static T_COUNT: u32 = 28;
|
||||
static N_COUNT: u32 = (V_COUNT * T_COUNT);
|
||||
static S_COUNT: u32 = (L_COUNT * N_COUNT);
|
||||
|
||||
// Decompose a precomposed Hangul syllable
|
||||
fn decompose_hangul(s: char, f: |char|) {
|
||||
use cast::transmute;
|
||||
|
||||
let si = s as u32 - S_BASE;
|
||||
|
||||
let li = si / N_COUNT;
|
||||
unsafe {
|
||||
f(transmute(L_BASE + li));
|
||||
|
||||
let vi = (si % N_COUNT) / T_COUNT;
|
||||
f(transmute(V_BASE + vi));
|
||||
|
||||
let ti = si % T_COUNT;
|
||||
if ti > 0 {
|
||||
f(transmute(T_BASE + ti));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
""")
|
||||
|
||||
def emit_std_norm_module(f, combine):
|
||||
f.write("pub mod normalization {\n");
|
||||
f.write(" use option::{Some, None};\n");
|
||||
f.write(" use slice::ImmutableVector;\n");
|
||||
|
||||
f.write("""
|
||||
fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 {
|
||||
use cmp::{Equal, Less, Greater};
|
||||
match r.bsearch(|&(lo, hi, _)| {
|
||||
if lo <= c && c <= hi { Equal }
|
||||
else if hi < c { Less }
|
||||
else { Greater }
|
||||
}) {
|
||||
Some(idx) => {
|
||||
let (_, _, result) = r[idx];
|
||||
result
|
||||
}
|
||||
None => 0
|
||||
}
|
||||
}\n\n
|
||||
""")
|
||||
|
||||
f.write(" static combining_class_table : &'static [(char, char, u8)] = &[\n")
|
||||
ix = 0
|
||||
for pair in combine:
|
||||
f.write(ch_prefix(ix))
|
||||
f.write("(%s, %s, %s)" % (escape_char(pair[0]), escape_char(pair[1]), pair[2]))
|
||||
ix += 1
|
||||
f.write("\n ];\n\n")
|
||||
|
||||
f.write(" pub fn canonical_combining_class(c: char) -> u8 {\n"
|
||||
+ " bsearch_range_value_table(c, combining_class_table)\n"
|
||||
+ " }\n")
|
||||
f.write("}\n")
|
||||
f.write("}\n\n")
|
||||
|
||||
r = "unicode.rs"
|
||||
for i in [r]:
|
||||
if os.path.exists(i):
|
||||
os.remove(i);
|
||||
rf = open(r, "w")
|
||||
|
||||
(canon_decomp, compat_decomp, gencats,
|
||||
combines, lowerupper, upperlower) = load_unicode_data("UnicodeData.txt")
|
||||
|
||||
# Preamble
|
||||
rf.write('''// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
preamble = '''// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
@ -409,17 +447,27 @@ rf.write('''// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGH
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// The following code was generated by "src/etc/unicode.py"
|
||||
// NOTE: The following code was generated by "src/etc/unicode.py", do not edit directly
|
||||
|
||||
#![allow(missing_doc)]
|
||||
#![allow(non_uppercase_statics)]
|
||||
#![allow(missing_doc, non_uppercase_statics)]
|
||||
|
||||
''')
|
||||
'''
|
||||
|
||||
(canon_decomp, compat_decomp, gencats,
|
||||
combines, lowerupper, upperlower) = load_unicode_data("UnicodeData.txt")
|
||||
|
||||
def gen_core_unicode():
|
||||
r = "core_unicode.rs"
|
||||
if os.path.exists(r):
|
||||
os.remove(r);
|
||||
with open(r, "w") as rf:
|
||||
# Preamble
|
||||
rf.write(preamble)
|
||||
|
||||
emit_bsearch_range_table(rf);
|
||||
emit_property_module(rf, "general_category", gencats)
|
||||
|
||||
emit_decomp_module(rf, canon_decomp, compat_decomp, combines)
|
||||
emit_core_norm_module(rf, canon_decomp, compat_decomp)
|
||||
|
||||
derived = load_properties("DerivedCoreProperties.txt",
|
||||
["XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase"])
|
||||
|
@ -429,3 +477,15 @@ emit_property_module(rf, "derived_property", derived)
|
|||
props = load_properties("PropList.txt", ["White_Space"])
|
||||
emit_property_module(rf, "property", props)
|
||||
emit_conversions_module(rf, lowerupper, upperlower)
|
||||
|
||||
def gen_std_unicode():
|
||||
r = "std_unicode.rs"
|
||||
if os.path.exists(r):
|
||||
os.remove(r);
|
||||
with open(r, "w") as rf:
|
||||
# Preamble
|
||||
rf.write(preamble)
|
||||
emit_std_norm_module(rf, combines)
|
||||
|
||||
gen_core_unicode()
|
||||
gen_std_unicode()
|
||||
|
|
|
@ -22,11 +22,8 @@
|
|||
|
||||
use mem::{transmute, transmute_copy};
|
||||
use option::{Option, Some, None};
|
||||
use owned::Box;
|
||||
use raw::TraitObject;
|
||||
use result::{Result, Ok, Err};
|
||||
use intrinsics::TypeId;
|
||||
use intrinsics;
|
||||
|
||||
/// A type with no inhabitants
|
||||
pub enum Void { }
|
||||
|
@ -117,38 +114,11 @@ impl<'a> AnyMutRefExt<'a> for &'a mut Any {
|
|||
}
|
||||
}
|
||||
|
||||
/// Extension methods for an owning `Any` trait object
|
||||
pub trait AnyOwnExt {
|
||||
/// Returns the boxed value if it is of type `T`, or
|
||||
/// `Err(Self)` if it isn't.
|
||||
fn move<T: 'static>(self) -> Result<Box<T>, Self>;
|
||||
}
|
||||
|
||||
impl AnyOwnExt for Box<Any> {
|
||||
#[inline]
|
||||
fn move<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
|
||||
if self.is::<T>() {
|
||||
unsafe {
|
||||
// Get the raw representation of the trait object
|
||||
let to: TraitObject = transmute_copy(&self);
|
||||
|
||||
// Prevent destructor on self being run
|
||||
intrinsics::forget(self);
|
||||
|
||||
// Extract the data pointer
|
||||
Ok(transmute(to.data))
|
||||
}
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use prelude::*;
|
||||
use super::*;
|
||||
use owned::Box;
|
||||
use realstd::owned::{Box, AnyOwnExt};
|
||||
use realstd::str::StrAllocating;
|
||||
|
||||
#[deriving(Eq, Show)]
|
||||
|
@ -253,6 +223,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn any_move() {
|
||||
use realstd::any::Any;
|
||||
use realstd::result::{Ok, Err};
|
||||
let a = box 8u as Box<Any>;
|
||||
let b = box Test as Box<Any>;
|
||||
|
||||
|
|
|
@ -27,19 +27,25 @@
|
|||
use mem::transmute;
|
||||
use option::{None, Option, Some};
|
||||
use iter::{Iterator, range_step};
|
||||
use unicode::{derived_property, property, general_category, decompose, conversions};
|
||||
use unicode::{derived_property, property, general_category, conversions};
|
||||
|
||||
/// Returns the canonical decomposition of a character.
|
||||
pub use unicode::normalization::decompose_canonical;
|
||||
/// Returns the compatibility decomposition of a character.
|
||||
pub use unicode::normalization::decompose_compatible;
|
||||
|
||||
#[cfg(not(test))] use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering};
|
||||
#[cfg(not(test))] use default::Default;
|
||||
|
||||
// UTF-8 ranges and tags for encoding characters
|
||||
static TAG_CONT: uint = 128u;
|
||||
static MAX_ONE_B: uint = 128u;
|
||||
static TAG_TWO_B: uint = 192u;
|
||||
static MAX_TWO_B: uint = 2048u;
|
||||
static TAG_THREE_B: uint = 224u;
|
||||
static MAX_THREE_B: uint = 65536u;
|
||||
static TAG_FOUR_B: uint = 240u;
|
||||
static TAG_CONT: u8 = 0b1000_0000u8;
|
||||
static TAG_TWO_B: u8 = 0b1100_0000u8;
|
||||
static TAG_THREE_B: u8 = 0b1110_0000u8;
|
||||
static TAG_FOUR_B: u8 = 0b1111_0000u8;
|
||||
static MAX_ONE_B: u32 = 0x80u32;
|
||||
static MAX_TWO_B: u32 = 0x800u32;
|
||||
static MAX_THREE_B: u32 = 0x10000u32;
|
||||
static MAX_FOUR_B: u32 = 0x200000u32;
|
||||
|
||||
/*
|
||||
Lu Uppercase_Letter an uppercase letter
|
||||
|
@ -284,53 +290,6 @@ pub fn from_digit(num: uint, radix: uint) -> Option<char> {
|
|||
}
|
||||
}
|
||||
|
||||
// Constants from Unicode 6.2.0 Section 3.12 Conjoining Jamo Behavior
|
||||
static S_BASE: uint = 0xAC00;
|
||||
static L_BASE: uint = 0x1100;
|
||||
static V_BASE: uint = 0x1161;
|
||||
static T_BASE: uint = 0x11A7;
|
||||
static L_COUNT: uint = 19;
|
||||
static V_COUNT: uint = 21;
|
||||
static T_COUNT: uint = 28;
|
||||
static N_COUNT: uint = (V_COUNT * T_COUNT);
|
||||
static S_COUNT: uint = (L_COUNT * N_COUNT);
|
||||
|
||||
// Decompose a precomposed Hangul syllable
|
||||
fn decompose_hangul(s: char, f: |char|) {
|
||||
let si = s as uint - S_BASE;
|
||||
|
||||
let li = si / N_COUNT;
|
||||
unsafe {
|
||||
f(transmute((L_BASE + li) as u32));
|
||||
|
||||
let vi = (si % N_COUNT) / T_COUNT;
|
||||
f(transmute((V_BASE + vi) as u32));
|
||||
|
||||
let ti = si % T_COUNT;
|
||||
if ti > 0 {
|
||||
f(transmute((T_BASE + ti) as u32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the canonical decomposition of a character
|
||||
pub fn decompose_canonical(c: char, f: |char|) {
|
||||
if (c as uint) < S_BASE || (c as uint) >= (S_BASE + S_COUNT) {
|
||||
decompose::canonical(c, f);
|
||||
} else {
|
||||
decompose_hangul(c, f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the compatibility decomposition of a character
|
||||
pub fn decompose_compatible(c: char, f: |char|) {
|
||||
if (c as uint) < S_BASE || (c as uint) >= (S_BASE + S_COUNT) {
|
||||
decompose::compatibility(c, f);
|
||||
} else {
|
||||
decompose_hangul(c, f);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the hexadecimal Unicode escape of a `char`
|
||||
///
|
||||
|
@ -386,12 +345,7 @@ pub fn escape_default(c: char, f: |char|) {
|
|||
|
||||
/// Returns the amount of bytes this `char` would need if encoded in UTF-8
|
||||
pub fn len_utf8_bytes(c: char) -> uint {
|
||||
static MAX_ONE_B: uint = 128u;
|
||||
static MAX_TWO_B: uint = 2048u;
|
||||
static MAX_THREE_B: uint = 65536u;
|
||||
static MAX_FOUR_B: uint = 2097152u;
|
||||
|
||||
let code = c as uint;
|
||||
let code = c as u32;
|
||||
match () {
|
||||
_ if code < MAX_ONE_B => 1u,
|
||||
_ if code < MAX_TWO_B => 2u,
|
||||
|
@ -606,41 +560,40 @@ impl Char for char {
|
|||
|
||||
fn len_utf8_bytes(&self) -> uint { len_utf8_bytes(*self) }
|
||||
|
||||
fn encode_utf8(&self, dst: &mut [u8]) -> uint {
|
||||
let code = *self as uint;
|
||||
fn encode_utf8<'a>(&self, dst: &'a mut [u8]) -> uint {
|
||||
let code = *self as u32;
|
||||
if code < MAX_ONE_B {
|
||||
dst[0] = code as u8;
|
||||
return 1;
|
||||
1
|
||||
} else if code < MAX_TWO_B {
|
||||
dst[0] = (code >> 6u & 31u | TAG_TWO_B) as u8;
|
||||
dst[1] = (code & 63u | TAG_CONT) as u8;
|
||||
return 2;
|
||||
dst[0] = (code >> 6u & 0x1F_u32) as u8 | TAG_TWO_B;
|
||||
dst[1] = (code & 0x3F_u32) as u8 | TAG_CONT;
|
||||
2
|
||||
} else if code < MAX_THREE_B {
|
||||
dst[0] = (code >> 12u & 15u | TAG_THREE_B) as u8;
|
||||
dst[1] = (code >> 6u & 63u | TAG_CONT) as u8;
|
||||
dst[2] = (code & 63u | TAG_CONT) as u8;
|
||||
return 3;
|
||||
dst[0] = (code >> 12u & 0x0F_u32) as u8 | TAG_THREE_B;
|
||||
dst[1] = (code >> 6u & 0x3F_u32) as u8 | TAG_CONT;
|
||||
dst[2] = (code & 0x3F_u32) as u8 | TAG_CONT;
|
||||
3
|
||||
} else {
|
||||
dst[0] = (code >> 18u & 7u | TAG_FOUR_B) as u8;
|
||||
dst[1] = (code >> 12u & 63u | TAG_CONT) as u8;
|
||||
dst[2] = (code >> 6u & 63u | TAG_CONT) as u8;
|
||||
dst[3] = (code & 63u | TAG_CONT) as u8;
|
||||
return 4;
|
||||
dst[0] = (code >> 18u & 0x07_u32) as u8 | TAG_FOUR_B;
|
||||
dst[1] = (code >> 12u & 0x3F_u32) as u8 | TAG_CONT;
|
||||
dst[2] = (code >> 6u & 0x3F_u32) as u8 | TAG_CONT;
|
||||
dst[3] = (code & 0x3F_u32) as u8 | TAG_CONT;
|
||||
4
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_utf16(&self, dst: &mut [u16]) -> uint {
|
||||
let mut ch = *self as uint;
|
||||
if (ch & 0xFFFF_u) == ch {
|
||||
// The BMP falls through (assuming non-surrogate, as it
|
||||
// should)
|
||||
assert!(ch <= 0xD7FF_u || ch >= 0xE000_u);
|
||||
let mut ch = *self as u32;
|
||||
if (ch & 0xFFFF_u32) == ch {
|
||||
// The BMP falls through (assuming non-surrogate, as it should)
|
||||
assert!(ch <= 0xD7FF_u32 || ch >= 0xE000_u32);
|
||||
dst[0] = ch as u16;
|
||||
1
|
||||
} else {
|
||||
// Supplementary planes break into surrogates.
|
||||
assert!(ch >= 0x1_0000_u && ch <= 0x10_FFFF_u);
|
||||
ch -= 0x1_0000_u;
|
||||
assert!(ch >= 0x1_0000_u32 && ch <= 0x10_FFFF_u32);
|
||||
ch -= 0x1_0000_u32;
|
||||
dst[0] = 0xD800_u16 | ((ch >> 10) as u16);
|
||||
dst[1] = 0xDC00_u16 | ((ch as u16) & 0x3FF_u16);
|
||||
2
|
||||
|
|
|
@ -21,8 +21,6 @@ the `clone` method.
|
|||
|
||||
*/
|
||||
|
||||
use owned::Box;
|
||||
|
||||
/// A common trait for cloning an object.
|
||||
pub trait Clone {
|
||||
/// Returns a copy of the value. The contents of owned pointers
|
||||
|
@ -41,18 +39,6 @@ pub trait Clone {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for Box<T> {
|
||||
/// Return a copy of the owned box.
|
||||
#[inline]
|
||||
fn clone(&self) -> Box<T> { box {(**self).clone()} }
|
||||
|
||||
/// Perform copy-assignment from `source` by reusing the existing allocation.
|
||||
#[inline]
|
||||
fn clone_from(&mut self, source: &Box<T>) {
|
||||
(**self).clone_from(&(**source));
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for @T {
|
||||
/// Return a shallow copy of the managed box.
|
||||
#[inline]
|
||||
|
@ -129,12 +115,22 @@ extern_fn_clone!(A, B, C, D, E, F, G, H)
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use prelude::*;
|
||||
use owned::Box;
|
||||
use realstd::owned::Box;
|
||||
|
||||
fn realclone<T: ::realstd::clone::Clone>(t: &T) -> T {
|
||||
use realstd::clone::Clone;
|
||||
t.clone()
|
||||
}
|
||||
|
||||
fn realclone_from<T: ::realstd::clone::Clone>(t1: &mut T, t2: &T) {
|
||||
use realstd::clone::Clone;
|
||||
t1.clone_from(t2)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_owned_clone() {
|
||||
let a = box 5i;
|
||||
let b: Box<int> = a.clone();
|
||||
let b: Box<int> = realclone(&a);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
|
@ -157,7 +153,7 @@ mod test {
|
|||
fn test_clone_from() {
|
||||
let a = box 5;
|
||||
let mut b = box 10;
|
||||
b.clone_from(&a);
|
||||
realclone_from(&mut b, &a);
|
||||
assert_eq!(*b, 5);
|
||||
}
|
||||
|
||||
|
|
|
@ -193,7 +193,6 @@ pub fn max<T: TotalOrd>(v1: T, v2: T) -> T {
|
|||
#[cfg(not(test))]
|
||||
mod impls {
|
||||
use cmp::{Ord, TotalOrd, Eq, TotalEq, Ordering};
|
||||
use owned::Box;
|
||||
|
||||
// & pointers
|
||||
impl<'a, T: Eq> Eq for &'a T {
|
||||
|
@ -240,29 +239,6 @@ mod impls {
|
|||
fn cmp(&self, other: &@T) -> Ordering { (**self).cmp(*other) }
|
||||
}
|
||||
impl<T: TotalEq> TotalEq for @T {}
|
||||
|
||||
// box pointers
|
||||
impl<T:Eq> Eq for Box<T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Box<T>) -> bool { *(*self) == *(*other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &Box<T>) -> bool { *(*self) != *(*other) }
|
||||
}
|
||||
impl<T:Ord> Ord for Box<T> {
|
||||
#[inline]
|
||||
fn lt(&self, other: &Box<T>) -> bool { *(*self) < *(*other) }
|
||||
#[inline]
|
||||
fn le(&self, other: &Box<T>) -> bool { *(*self) <= *(*other) }
|
||||
#[inline]
|
||||
fn ge(&self, other: &Box<T>) -> bool { *(*self) >= *(*other) }
|
||||
#[inline]
|
||||
fn gt(&self, other: &Box<T>) -> bool { *(*self) > *(*other) }
|
||||
}
|
||||
impl<T: TotalOrd> TotalOrd for Box<T> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Box<T>) -> Ordering { (**self).cmp(*other) }
|
||||
}
|
||||
impl<T: TotalEq> TotalEq for Box<T> {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
|
||||
//! The `Default` trait for types which may have meaningful default values
|
||||
|
||||
use owned::Box;
|
||||
|
||||
/// A trait that types which have a useful default value should implement.
|
||||
pub trait Default {
|
||||
/// Return the "default value" for a type.
|
||||
|
@ -21,7 +19,3 @@ pub trait Default {
|
|||
impl<T: Default + 'static> Default for @T {
|
||||
fn default() -> @T { @Default::default() }
|
||||
}
|
||||
|
||||
impl<T: Default> Default for Box<T> {
|
||||
fn default() -> Box<T> { box Default::default() }
|
||||
}
|
||||
|
|
|
@ -2334,7 +2334,7 @@ mod tests {
|
|||
use realstd::num;
|
||||
|
||||
use cmp;
|
||||
use owned::Box;
|
||||
use realstd::owned::Box;
|
||||
use uint;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#[cfg(test)] pub use cmp = realcore::cmp;
|
||||
#[cfg(test)] pub use kinds = realcore::kinds;
|
||||
#[cfg(test)] pub use ops = realcore::ops;
|
||||
#[cfg(test)] pub use owned = realcore::owned;
|
||||
#[cfg(test)] pub use ty = realcore::ty;
|
||||
|
||||
#[cfg(not(test))]
|
||||
|
@ -73,7 +72,6 @@ pub mod ptr;
|
|||
#[cfg(not(test))] pub mod ops;
|
||||
#[cfg(not(test))] pub mod ty;
|
||||
#[cfg(not(test))] pub mod cmp;
|
||||
#[cfg(not(test))] pub mod owned;
|
||||
pub mod clone;
|
||||
pub mod default;
|
||||
pub mod container;
|
||||
|
@ -95,6 +93,9 @@ pub mod slice;
|
|||
pub mod str;
|
||||
pub mod tuple;
|
||||
|
||||
#[cfg(stage0, not(test))]
|
||||
pub mod owned;
|
||||
|
||||
mod failure;
|
||||
|
||||
// FIXME: this module should not exist. Once owned allocations are no longer a
|
||||
|
|
|
@ -380,7 +380,7 @@ mod tests {
|
|||
use mem::*;
|
||||
use option::{Some,None};
|
||||
use realstd::str::StrAllocating;
|
||||
use owned::Box;
|
||||
use realstd::owned::Box;
|
||||
use raw;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -10,10 +10,14 @@
|
|||
|
||||
//! Operations on unique pointer types
|
||||
|
||||
// FIXME: this module should not exist in libcore. It must currently because the
|
||||
// Box implementation is quite ad-hoc in the compiler. Once there is
|
||||
// proper support in the compiler this type will be able to be defined in
|
||||
// its own module.
|
||||
use any::{Any, AnyRefExt};
|
||||
use clone::Clone;
|
||||
use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering};
|
||||
use default::Default;
|
||||
use intrinsics;
|
||||
use mem;
|
||||
use raw::TraitObject;
|
||||
use result::{Ok, Err, 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.
|
||||
|
@ -23,16 +27,75 @@
|
|||
/// let foo = box(HEAP) Bar::new(...);
|
||||
/// let foo = box Bar::new(...);
|
||||
#[lang="exchange_heap"]
|
||||
#[cfg(not(test))]
|
||||
pub static HEAP: () = ();
|
||||
|
||||
#[cfg(test)]
|
||||
pub static HEAP: () = ();
|
||||
|
||||
/// A type that represents a uniquely-owned value.
|
||||
#[lang="owned_box"]
|
||||
#[cfg(not(test))]
|
||||
pub struct Box<T>(*T);
|
||||
|
||||
#[cfg(test)]
|
||||
pub struct Box<T>(*T);
|
||||
impl<T: Default> Default for Box<T> {
|
||||
fn default() -> Box<T> { box Default::default() }
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for Box<T> {
|
||||
/// Return a copy of the owned box.
|
||||
#[inline]
|
||||
fn clone(&self) -> Box<T> { box {(**self).clone()} }
|
||||
|
||||
/// Perform copy-assignment from `source` by reusing the existing allocation.
|
||||
#[inline]
|
||||
fn clone_from(&mut self, source: &Box<T>) {
|
||||
(**self).clone_from(&(**source));
|
||||
}
|
||||
}
|
||||
|
||||
// box pointers
|
||||
impl<T:Eq> Eq for Box<T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Box<T>) -> bool { *(*self) == *(*other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &Box<T>) -> bool { *(*self) != *(*other) }
|
||||
}
|
||||
impl<T:Ord> Ord for Box<T> {
|
||||
#[inline]
|
||||
fn lt(&self, other: &Box<T>) -> bool { *(*self) < *(*other) }
|
||||
#[inline]
|
||||
fn le(&self, other: &Box<T>) -> bool { *(*self) <= *(*other) }
|
||||
#[inline]
|
||||
fn ge(&self, other: &Box<T>) -> bool { *(*self) >= *(*other) }
|
||||
#[inline]
|
||||
fn gt(&self, other: &Box<T>) -> bool { *(*self) > *(*other) }
|
||||
}
|
||||
impl<T: TotalOrd> TotalOrd for Box<T> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Box<T>) -> Ordering { (**self).cmp(*other) }
|
||||
}
|
||||
impl<T: TotalEq> TotalEq for Box<T> {}
|
||||
|
||||
/// Extension methods for an owning `Any` trait object
|
||||
pub trait AnyOwnExt {
|
||||
/// Returns the boxed value if it is of type `T`, or
|
||||
/// `Err(Self)` if it isn't.
|
||||
fn move<T: 'static>(self) -> Result<Box<T>, Self>;
|
||||
}
|
||||
|
||||
impl AnyOwnExt for Box<Any> {
|
||||
#[inline]
|
||||
fn move<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
|
||||
if self.is::<T>() {
|
||||
unsafe {
|
||||
// Get the raw representation of the trait object
|
||||
let to: TraitObject =
|
||||
*mem::transmute::<&Box<Any>, &TraitObject>(&self);
|
||||
|
||||
// Prevent destructor on self being run
|
||||
intrinsics::forget(self);
|
||||
|
||||
// Extract the data pointer
|
||||
Ok(mem::transmute(to.data))
|
||||
}
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1725,6 +1725,7 @@ impl<'a> StrSlice<'a> for &'a str {
|
|||
#[inline]
|
||||
fn is_char_boundary(&self, index: uint) -> bool {
|
||||
if index == self.len() { return true; }
|
||||
if index > self.len() { return false; }
|
||||
let b = self[index];
|
||||
return b < 128u8 || b >= 192u8;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
@ -8,10 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// The following code was generated by "src/etc/unicode.py"
|
||||
// NOTE: The following code was generated by "src/etc/unicode.py", do not edit directly
|
||||
|
||||
#![allow(missing_doc, non_uppercase_statics)]
|
||||
|
||||
|
||||
fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
|
||||
use cmp::{Equal, Less, Greater};
|
||||
use slice::ImmutableVector;
|
||||
|
@ -102,7 +103,8 @@ pub mod general_category {
|
|||
}
|
||||
|
||||
}
|
||||
pub mod decompose {
|
||||
|
||||
pub mod normalization {
|
||||
use option::Option;
|
||||
use option::{Some, None};
|
||||
use slice::ImmutableVector;
|
||||
|
@ -123,7 +125,6 @@ pub mod decompose {
|
|||
}
|
||||
|
||||
|
||||
|
||||
// Canonical decompositions
|
||||
static canonical_table : &'static [(char, &'static [char])] = &[
|
||||
('\xc0', &['\x41', '\u0300']), ('\xc1', &['\x41', '\u0301']), ('\xc2', &['\x41', '\u0302']),
|
||||
|
@ -2120,14 +2121,24 @@ pub mod decompose {
|
|||
&['\u53ef'])
|
||||
];
|
||||
|
||||
pub fn canonical(c: char, i: |char|) { d(c, i, false); }
|
||||
|
||||
pub fn compatibility(c: char, i: |char|) { d(c, i, true); }
|
||||
pub fn decompose_canonical(c: char, i: |char|) { d(c, i, false); }
|
||||
|
||||
pub fn decompose_compatible(c: char, i: |char|) { d(c, i, true); }
|
||||
|
||||
fn d(c: char, i: |char|, k: bool) {
|
||||
use iter::Iterator;
|
||||
|
||||
// 7-bit ASCII never decomposes
|
||||
if c <= '\x7f' { i(c); return; }
|
||||
|
||||
// Perform decomposition for Hangul
|
||||
if (c as u32) >= S_BASE && (c as u32) < (S_BASE + S_COUNT) {
|
||||
decompose_hangul(c, i);
|
||||
return;
|
||||
}
|
||||
|
||||
// First check the canonical decompositions
|
||||
match bsearch_table(c, canonical_table) {
|
||||
Some(canon) => {
|
||||
for x in canon.iter() {
|
||||
|
@ -2138,8 +2149,10 @@ pub mod decompose {
|
|||
None => ()
|
||||
}
|
||||
|
||||
// Bottom out if we're not doing compat.
|
||||
if !k { i(c); return; }
|
||||
|
||||
// Then check the compatibility decompositions
|
||||
match bsearch_table(c, compatibility_table) {
|
||||
Some(compat) => {
|
||||
for x in compat.iter() {
|
||||
|
@ -2150,8 +2163,40 @@ pub mod decompose {
|
|||
None => ()
|
||||
}
|
||||
|
||||
// Finally bottom out.
|
||||
i(c);
|
||||
}
|
||||
|
||||
// Constants from Unicode 6.2.0 Section 3.12 Conjoining Jamo Behavior
|
||||
static S_BASE: u32 = 0xAC00;
|
||||
static L_BASE: u32 = 0x1100;
|
||||
static V_BASE: u32 = 0x1161;
|
||||
static T_BASE: u32 = 0x11A7;
|
||||
static L_COUNT: u32 = 19;
|
||||
static V_COUNT: u32 = 21;
|
||||
static T_COUNT: u32 = 28;
|
||||
static N_COUNT: u32 = (V_COUNT * T_COUNT);
|
||||
static S_COUNT: u32 = (L_COUNT * N_COUNT);
|
||||
|
||||
// Decompose a precomposed Hangul syllable
|
||||
fn decompose_hangul(s: char, f: |char|) {
|
||||
use mem::transmute;
|
||||
|
||||
let si = s as u32 - S_BASE;
|
||||
|
||||
let li = si / N_COUNT;
|
||||
unsafe {
|
||||
f(transmute(L_BASE + li));
|
||||
|
||||
let vi = (si % N_COUNT) / T_COUNT;
|
||||
f(transmute(V_BASE + vi));
|
||||
|
||||
let ti = si % T_COUNT;
|
||||
if ti > 0 {
|
||||
f(transmute(T_BASE + ti));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod derived_property {
|
||||
|
@ -3968,6 +4013,7 @@ pub mod derived_property {
|
|||
pub fn XID_Start(c: char) -> bool {
|
||||
super::bsearch_range_table(c, XID_Start_table)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub mod property {
|
||||
|
@ -3983,6 +4029,7 @@ pub mod property {
|
|||
pub fn White_Space(c: char) -> bool {
|
||||
super::bsearch_range_table(c, White_Space_table)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub mod conversions {
|
||||
|
|
|
@ -173,7 +173,7 @@ pub use funcs::bsd43::{shutdown};
|
|||
#[cfg(unix)] pub use consts::os::posix88::{EADDRINUSE, ENOENT, EISDIR, EAGAIN, EWOULDBLOCK};
|
||||
#[cfg(unix)] pub use consts::os::posix88::{ECANCELED, SIGINT, EINPROGRESS};
|
||||
#[cfg(unix)] pub use consts::os::posix88::{SIGTERM, SIGKILL, SIGPIPE, PROT_NONE};
|
||||
#[cfg(unix)] pub use consts::os::posix01::{SIG_IGN, WNOHANG};
|
||||
#[cfg(unix)] pub use consts::os::posix01::{SIG_IGN};
|
||||
#[cfg(unix)] pub use consts::os::bsd44::{AF_UNIX};
|
||||
|
||||
#[cfg(unix)] pub use types::os::common::posix01::{pthread_t, timespec, timezone};
|
||||
|
@ -2473,8 +2473,6 @@ pub mod consts {
|
|||
|
||||
pub static CLOCK_REALTIME: c_int = 0;
|
||||
pub static CLOCK_MONOTONIC: c_int = 1;
|
||||
|
||||
pub static WNOHANG: c_int = 1;
|
||||
}
|
||||
pub mod posix08 {
|
||||
}
|
||||
|
@ -2924,8 +2922,6 @@ pub mod consts {
|
|||
|
||||
pub static CLOCK_REALTIME: c_int = 0;
|
||||
pub static CLOCK_MONOTONIC: c_int = 4;
|
||||
|
||||
pub static WNOHANG: c_int = 1;
|
||||
}
|
||||
pub mod posix08 {
|
||||
}
|
||||
|
@ -3313,8 +3309,6 @@ pub mod consts {
|
|||
pub static PTHREAD_CREATE_JOINABLE: c_int = 1;
|
||||
pub static PTHREAD_CREATE_DETACHED: c_int = 2;
|
||||
pub static PTHREAD_STACK_MIN: size_t = 8192;
|
||||
|
||||
pub static WNOHANG: c_int = 1;
|
||||
}
|
||||
pub mod posix08 {
|
||||
}
|
||||
|
@ -3980,16 +3974,6 @@ pub mod funcs {
|
|||
}
|
||||
}
|
||||
|
||||
pub mod wait {
|
||||
use types::os::arch::c95::{c_int};
|
||||
use types::os::arch::posix88::{pid_t};
|
||||
|
||||
extern {
|
||||
pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int)
|
||||
-> pid_t;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod glob {
|
||||
use types::os::arch::c95::{c_char, c_int};
|
||||
use types::os::common::posix01::{glob_t};
|
||||
|
|
|
@ -10,7 +10,12 @@
|
|||
|
||||
//! C definitions used by libnative that don't belong in liblibc
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub use self::select::fd_set;
|
||||
pub use self::signal::{sigaction, siginfo, sigset_t};
|
||||
pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP};
|
||||
pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD};
|
||||
|
||||
use libc;
|
||||
|
||||
|
@ -34,6 +39,8 @@ pub static MSG_DONTWAIT: libc::c_int = 0x80;
|
|||
#[cfg(target_os = "android")]
|
||||
pub static MSG_DONTWAIT: libc::c_int = 0x40;
|
||||
|
||||
pub static WNOHANG: libc::c_int = 1;
|
||||
|
||||
extern {
|
||||
pub fn gettimeofday(timeval: *mut libc::timeval,
|
||||
tzp: *libc::c_void) -> libc::c_int;
|
||||
|
@ -49,6 +56,17 @@ extern {
|
|||
optlen: *mut libc::socklen_t) -> libc::c_int;
|
||||
pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int;
|
||||
|
||||
|
||||
pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int,
|
||||
options: libc::c_int) -> libc::pid_t;
|
||||
|
||||
pub fn sigaction(signum: libc::c_int,
|
||||
act: *sigaction,
|
||||
oldact: *mut sigaction) -> libc::c_int;
|
||||
|
||||
pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
|
||||
pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
|
||||
pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -81,3 +99,94 @@ mod select {
|
|||
set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "android")]
|
||||
mod signal {
|
||||
use libc;
|
||||
|
||||
pub static SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
|
||||
pub static SA_NOCLDWAIT: libc::c_ulong = 0x00000002;
|
||||
pub static SA_NODEFER: libc::c_ulong = 0x40000000;
|
||||
pub static SA_ONSTACK: libc::c_ulong = 0x08000000;
|
||||
pub static SA_RESETHAND: libc::c_ulong = 0x80000000;
|
||||
pub static SA_RESTART: libc::c_ulong = 0x10000000;
|
||||
pub static SA_SIGINFO: libc::c_ulong = 0x00000004;
|
||||
pub static SIGCHLD: libc::c_int = 17;
|
||||
|
||||
// This definition is not as accurate as it could be, {pid, uid, status} is
|
||||
// actually a giant union. Currently we're only interested in these fields,
|
||||
// however.
|
||||
pub struct siginfo {
|
||||
si_signo: libc::c_int,
|
||||
si_errno: libc::c_int,
|
||||
si_code: libc::c_int,
|
||||
pub pid: libc::pid_t,
|
||||
pub uid: libc::uid_t,
|
||||
pub status: libc::c_int,
|
||||
}
|
||||
|
||||
pub struct sigaction {
|
||||
pub sa_handler: extern fn(libc::c_int),
|
||||
pub sa_mask: sigset_t,
|
||||
pub sa_flags: libc::c_ulong,
|
||||
sa_restorer: *mut libc::c_void,
|
||||
}
|
||||
|
||||
#[cfg(target_word_size = "32")]
|
||||
pub struct sigset_t {
|
||||
__val: [libc::c_ulong, ..32],
|
||||
}
|
||||
#[cfg(target_word_size = "64")]
|
||||
pub struct sigset_t {
|
||||
__val: [libc::c_ulong, ..16],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
mod signal {
|
||||
use libc;
|
||||
|
||||
pub static SA_ONSTACK: libc::c_int = 0x0001;
|
||||
pub static SA_RESTART: libc::c_int = 0x0002;
|
||||
pub static SA_RESETHAND: libc::c_int = 0x0004;
|
||||
pub static SA_NOCLDSTOP: libc::c_int = 0x0008;
|
||||
pub static SA_NODEFER: libc::c_int = 0x0010;
|
||||
pub static SA_NOCLDWAIT: libc::c_int = 0x0020;
|
||||
pub static SA_SIGINFO: libc::c_int = 0x0040;
|
||||
pub static SIGCHLD: libc::c_int = 20;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub type sigset_t = u32;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
pub struct sigset_t {
|
||||
bits: [u32, ..4],
|
||||
}
|
||||
|
||||
// This structure has more fields, but we're not all that interested in
|
||||
// them.
|
||||
pub struct siginfo {
|
||||
pub si_signo: libc::c_int,
|
||||
pub si_errno: libc::c_int,
|
||||
pub si_code: libc::c_int,
|
||||
pub pid: libc::pid_t,
|
||||
pub uid: libc::uid_t,
|
||||
pub status: libc::c_int,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub struct sigaction {
|
||||
pub sa_handler: extern fn(libc::c_int),
|
||||
sa_tramp: *mut libc::c_void,
|
||||
pub sa_mask: sigset_t,
|
||||
pub sa_flags: libc::c_int,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
pub struct sigaction {
|
||||
pub sa_handler: extern fn(libc::c_int),
|
||||
pub sa_flags: libc::c_int,
|
||||
pub sa_mask: sigset_t,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <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.
|
||||
|
||||
//! Implementation of the helper thread for the timer module
|
||||
//!
|
||||
//! This module contains the management necessary for the timer worker thread.
|
||||
//! This thread is responsible for performing the send()s on channels for timers
|
||||
//! that are using channels instead of a blocking call.
|
||||
//!
|
||||
//! The timer thread is lazily initialized, and it's shut down via the
|
||||
//! `shutdown` function provided. It must be maintained as an invariant that
|
||||
//! `shutdown` is only called when the entire program is finished. No new timers
|
||||
//! can be created in the future and there must be no active timers at that
|
||||
//! time.
|
||||
|
||||
#![macro_escape]
|
||||
|
||||
use std::mem;
|
||||
use std::rt::bookkeeping;
|
||||
use std::rt;
|
||||
use std::ty::Unsafe;
|
||||
use std::unstable::mutex::StaticNativeMutex;
|
||||
|
||||
use task;
|
||||
|
||||
/// A structure for management of a helper thread.
|
||||
///
|
||||
/// This is generally a static structure which tracks the lifetime of a helper
|
||||
/// thread.
|
||||
///
|
||||
/// The fields of this helper are all public, but they should not be used, this
|
||||
/// is for static initialization.
|
||||
pub struct Helper<M> {
|
||||
/// Internal lock which protects the remaining fields
|
||||
pub lock: StaticNativeMutex,
|
||||
|
||||
// You'll notice that the remaining fields are Unsafe<T>, and this is
|
||||
// because all helper thread operations are done through &self, but we need
|
||||
// these to be mutable (once `lock` is held).
|
||||
|
||||
/// Lazily allocated channel to send messages to the helper thread.
|
||||
pub chan: Unsafe<*mut Sender<M>>,
|
||||
|
||||
/// OS handle used to wake up a blocked helper thread
|
||||
pub signal: Unsafe<uint>,
|
||||
|
||||
/// Flag if this helper thread has booted and been initialized yet.
|
||||
pub initialized: Unsafe<bool>,
|
||||
}
|
||||
|
||||
macro_rules! helper_init( (static mut $name:ident: Helper<$m:ty>) => (
|
||||
static mut $name: Helper<$m> = Helper {
|
||||
lock: ::std::unstable::mutex::NATIVE_MUTEX_INIT,
|
||||
chan: ::std::ty::Unsafe {
|
||||
value: 0 as *mut Sender<$m>,
|
||||
marker1: ::std::kinds::marker::InvariantType,
|
||||
},
|
||||
signal: ::std::ty::Unsafe {
|
||||
value: 0,
|
||||
marker1: ::std::kinds::marker::InvariantType,
|
||||
},
|
||||
initialized: ::std::ty::Unsafe {
|
||||
value: false,
|
||||
marker1: ::std::kinds::marker::InvariantType,
|
||||
},
|
||||
};
|
||||
) )
|
||||
|
||||
impl<M: Send> Helper<M> {
|
||||
/// Lazily boots a helper thread, becoming a no-op if the helper has already
|
||||
/// been spawned.
|
||||
///
|
||||
/// This function will check to see if the thread has been initialized, and
|
||||
/// if it has it returns quickly. If initialization has not happened yet,
|
||||
/// the closure `f` will be run (inside of the initialization lock) and
|
||||
/// passed to the helper thread in a separate task.
|
||||
///
|
||||
/// This function is safe to be called many times.
|
||||
pub fn boot<T: Send>(&'static self,
|
||||
f: || -> T,
|
||||
helper: fn(imp::signal, Receiver<M>, T)) {
|
||||
unsafe {
|
||||
let _guard = self.lock.lock();
|
||||
if !*self.initialized.get() {
|
||||
let (tx, rx) = channel();
|
||||
*self.chan.get() = mem::transmute(box tx);
|
||||
let (receive, send) = imp::new();
|
||||
*self.signal.get() = send as uint;
|
||||
|
||||
let t = f();
|
||||
task::spawn(proc() {
|
||||
bookkeeping::decrement();
|
||||
helper(receive, rx, t);
|
||||
self.lock.lock().signal()
|
||||
});
|
||||
|
||||
rt::at_exit(proc() { self.shutdown() });
|
||||
*self.initialized.get() = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends a message to a spawned worker thread.
|
||||
///
|
||||
/// This is only valid if the worker thread has previously booted
|
||||
pub fn send(&'static self, msg: M) {
|
||||
unsafe {
|
||||
let _guard = self.lock.lock();
|
||||
|
||||
// Must send and *then* signal to ensure that the child receives the
|
||||
// message. Otherwise it could wake up and go to sleep before we
|
||||
// send the message.
|
||||
assert!(!self.chan.get().is_null());
|
||||
(**self.chan.get()).send(msg);
|
||||
imp::signal(*self.signal.get() as imp::signal);
|
||||
}
|
||||
}
|
||||
|
||||
fn shutdown(&'static self) {
|
||||
unsafe {
|
||||
// Shut down, but make sure this is done inside our lock to ensure
|
||||
// that we'll always receive the exit signal when the thread
|
||||
// returns.
|
||||
let guard = self.lock.lock();
|
||||
|
||||
// Close the channel by destroying it
|
||||
let chan: Box<Sender<M>> = mem::transmute(*self.chan.get());
|
||||
*self.chan.get() = 0 as *mut Sender<M>;
|
||||
drop(chan);
|
||||
imp::signal(*self.signal.get() as imp::signal);
|
||||
|
||||
// Wait for the child to exit
|
||||
guard.wait();
|
||||
drop(guard);
|
||||
|
||||
// Clean up after ourselves
|
||||
self.lock.destroy();
|
||||
imp::close(*self.signal.get() as imp::signal);
|
||||
*self.signal.get() = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
mod imp {
|
||||
use libc;
|
||||
use std::os;
|
||||
|
||||
use io::file::FileDesc;
|
||||
|
||||
pub type signal = libc::c_int;
|
||||
|
||||
pub fn new() -> (signal, signal) {
|
||||
let pipe = os::pipe();
|
||||
(pipe.input, pipe.out)
|
||||
}
|
||||
|
||||
pub fn signal(fd: libc::c_int) {
|
||||
FileDesc::new(fd, false).inner_write([0]).unwrap();
|
||||
}
|
||||
|
||||
pub fn close(fd: libc::c_int) {
|
||||
let _fd = FileDesc::new(fd, true);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
mod imp {
|
||||
use libc::{BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle};
|
||||
use std::ptr;
|
||||
use libc;
|
||||
|
||||
pub type signal = HANDLE;
|
||||
|
||||
pub fn new() -> (HANDLE, HANDLE) {
|
||||
unsafe {
|
||||
let handle = CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
|
||||
ptr::null());
|
||||
(handle, handle)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signal(handle: HANDLE) {
|
||||
assert!(unsafe { SetEvent(handle) != 0 });
|
||||
}
|
||||
|
||||
pub fn close(handle: HANDLE) {
|
||||
assert!(unsafe { CloseHandle(handle) != 0 });
|
||||
}
|
||||
|
||||
extern "system" {
|
||||
fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
|
||||
bManualReset: BOOL,
|
||||
bInitialState: BOOL,
|
||||
lpName: LPCSTR) -> HANDLE;
|
||||
fn SetEvent(hEvent: HANDLE) -> BOOL;
|
||||
}
|
||||
}
|
|
@ -40,6 +40,8 @@ use ai = std::io::net::addrinfo;
|
|||
pub use self::file::FileDesc;
|
||||
pub use self::process::Process;
|
||||
|
||||
mod helper_thread;
|
||||
|
||||
// Native I/O implementations
|
||||
pub mod addrinfo;
|
||||
pub mod net;
|
||||
|
@ -75,8 +77,6 @@ pub mod pipe;
|
|||
#[cfg(unix)] #[path = "c_unix.rs"] mod c;
|
||||
#[cfg(windows)] #[path = "c_win32.rs"] mod c;
|
||||
|
||||
mod timer_helper;
|
||||
|
||||
pub type IoResult<T> = Result<T, IoError>;
|
||||
|
||||
fn unimpl() -> IoError {
|
||||
|
|
|
@ -8,20 +8,27 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::io;
|
||||
use libc::{pid_t, c_void, c_int};
|
||||
use libc;
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::os;
|
||||
use std::ptr;
|
||||
use std::rt::rtio;
|
||||
use p = std::io::process;
|
||||
|
||||
|
||||
use super::IoResult;
|
||||
use super::file;
|
||||
use super::util;
|
||||
|
||||
#[cfg(windows)] use std::mem;
|
||||
#[cfg(windows)] use std::strbuf::StrBuf;
|
||||
#[cfg(not(windows))] use super::retry;
|
||||
#[cfg(unix)] use super::c;
|
||||
#[cfg(unix)] use super::retry;
|
||||
#[cfg(unix)] use io::helper_thread::Helper;
|
||||
|
||||
#[cfg(unix)]
|
||||
helper_init!(static mut HELPER: Helper<Req>)
|
||||
|
||||
/**
|
||||
* A value representing a child process.
|
||||
|
@ -44,6 +51,14 @@ pub struct Process {
|
|||
|
||||
/// Manually delivered signal
|
||||
exit_signal: Option<int>,
|
||||
|
||||
/// Deadline after which wait() will return
|
||||
deadline: u64,
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
enum Req {
|
||||
NewChild(libc::pid_t, Sender<p::ProcessExit>, u64),
|
||||
}
|
||||
|
||||
impl Process {
|
||||
|
@ -116,6 +131,7 @@ impl Process {
|
|||
handle: res.handle,
|
||||
exit_code: None,
|
||||
exit_signal: None,
|
||||
deadline: 0,
|
||||
},
|
||||
ret_io))
|
||||
}
|
||||
|
@ -131,11 +147,15 @@ impl Process {
|
|||
impl rtio::RtioProcess for Process {
|
||||
fn id(&self) -> pid_t { self.pid }
|
||||
|
||||
fn wait(&mut self) -> p::ProcessExit {
|
||||
fn set_timeout(&mut self, timeout: Option<u64>) {
|
||||
self.deadline = timeout.map(|i| i + ::io::timer::now()).unwrap_or(0);
|
||||
}
|
||||
|
||||
fn wait(&mut self) -> IoResult<p::ProcessExit> {
|
||||
match self.exit_code {
|
||||
Some(code) => code,
|
||||
Some(code) => Ok(code),
|
||||
None => {
|
||||
let code = waitpid(self.pid);
|
||||
let code = try!(waitpid(self.pid, self.deadline));
|
||||
// On windows, waitpid will never return a signal. If a signal
|
||||
// was successfully delivered to the process, however, we can
|
||||
// consider it as having died via a signal.
|
||||
|
@ -145,7 +165,7 @@ impl rtio::RtioProcess for Process {
|
|||
Some(..) => code,
|
||||
};
|
||||
self.exit_code = Some(code);
|
||||
code
|
||||
Ok(code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -762,11 +782,8 @@ fn translate_status(status: c_int) -> p::ProcessExit {
|
|||
* operate on a none-existent process or, even worse, on a newer process
|
||||
* with the same id.
|
||||
*/
|
||||
fn waitpid(pid: pid_t) -> p::ProcessExit {
|
||||
return waitpid_os(pid);
|
||||
|
||||
#[cfg(windows)]
|
||||
fn waitpid_os(pid: pid_t) -> p::ProcessExit {
|
||||
fn waitpid(pid: pid_t, deadline: u64) -> IoResult<p::ProcessExit> {
|
||||
use libc::types::os::arch::extra::DWORD;
|
||||
use libc::consts::os::extra::{
|
||||
SYNCHRONIZE,
|
||||
|
@ -774,49 +791,292 @@ fn waitpid(pid: pid_t) -> p::ProcessExit {
|
|||
FALSE,
|
||||
STILL_ACTIVE,
|
||||
INFINITE,
|
||||
WAIT_FAILED
|
||||
WAIT_TIMEOUT,
|
||||
WAIT_OBJECT_0,
|
||||
};
|
||||
use libc::funcs::extra::kernel32::{
|
||||
OpenProcess,
|
||||
GetExitCodeProcess,
|
||||
CloseHandle,
|
||||
WaitForSingleObject
|
||||
WaitForSingleObject,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
|
||||
let process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
|
||||
FALSE,
|
||||
pid as DWORD);
|
||||
if process.is_null() {
|
||||
fail!("failure in OpenProcess: {}", os::last_os_error());
|
||||
return Err(super::last_error())
|
||||
}
|
||||
|
||||
loop {
|
||||
let mut status = 0;
|
||||
if GetExitCodeProcess(process, &mut status) == FALSE {
|
||||
let err = Err(super::last_error());
|
||||
assert!(CloseHandle(process) != 0);
|
||||
fail!("failure in GetExitCodeProcess: {}", os::last_os_error());
|
||||
return err;
|
||||
}
|
||||
if status != STILL_ACTIVE {
|
||||
assert!(CloseHandle(process) != 0);
|
||||
return p::ExitStatus(status as int);
|
||||
return Ok(p::ExitStatus(status as int));
|
||||
}
|
||||
if WaitForSingleObject(process, INFINITE) == WAIT_FAILED {
|
||||
let interval = if deadline == 0 {
|
||||
INFINITE
|
||||
} else {
|
||||
let now = ::io::timer::now();
|
||||
if deadline < now {0} else {(deadline - now) as u32}
|
||||
};
|
||||
match WaitForSingleObject(process, interval) {
|
||||
WAIT_OBJECT_0 => {}
|
||||
WAIT_TIMEOUT => {
|
||||
assert!(CloseHandle(process) != 0);
|
||||
fail!("failure in WaitForSingleObject: {}", os::last_os_error());
|
||||
return Err(util::timeout("process wait timed out"))
|
||||
}
|
||||
_ => {
|
||||
let err = Err(super::last_error());
|
||||
assert!(CloseHandle(process) != 0);
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn waitpid_os(pid: pid_t) -> p::ProcessExit {
|
||||
use libc::funcs::posix01::wait;
|
||||
fn waitpid(pid: pid_t, deadline: u64) -> IoResult<p::ProcessExit> {
|
||||
use std::cmp;
|
||||
use std::comm;
|
||||
|
||||
static mut WRITE_FD: libc::c_int = 0;
|
||||
|
||||
let mut status = 0 as c_int;
|
||||
match retry(|| unsafe { wait::waitpid(pid, &mut status, 0) }) {
|
||||
if deadline == 0 {
|
||||
return match retry(|| unsafe { c::waitpid(pid, &mut status, 0) }) {
|
||||
-1 => fail!("unknown waitpid error: {}", super::last_error()),
|
||||
_ => translate_status(status),
|
||||
_ => Ok(translate_status(status)),
|
||||
}
|
||||
}
|
||||
|
||||
// On unix, wait() and its friends have no timeout parameters, so there is
|
||||
// no way to time out a thread in wait(). From some googling and some
|
||||
// thinking, it appears that there are a few ways to handle timeouts in
|
||||
// wait(), but the only real reasonable one for a multi-threaded program is
|
||||
// to listen for SIGCHLD.
|
||||
//
|
||||
// With this in mind, the waiting mechanism with a timeout barely uses
|
||||
// waitpid() at all. There are a few times that waitpid() is invoked with
|
||||
// WNOHANG, but otherwise all the necessary blocking is done by waiting for
|
||||
// a SIGCHLD to arrive (and that blocking has a timeout). Note, however,
|
||||
// that waitpid() is still used to actually reap the child.
|
||||
//
|
||||
// Signal handling is super tricky in general, and this is no exception. Due
|
||||
// to the async nature of SIGCHLD, we use the self-pipe trick to transmit
|
||||
// data out of the signal handler to the rest of the application. The first
|
||||
// idea would be to have each thread waiting with a timeout to read this
|
||||
// output file descriptor, but a write() is akin to a signal(), not a
|
||||
// broadcast(), so it would only wake up one thread, and possibly the wrong
|
||||
// thread. Hence a helper thread is used.
|
||||
//
|
||||
// The helper thread here is responsible for farming requests for a
|
||||
// waitpid() with a timeout, and then processing all of the wait requests.
|
||||
// By guaranteeing that only this helper thread is reading half of the
|
||||
// self-pipe, we're sure that we'll never lose a SIGCHLD. This helper thread
|
||||
// is also responsible for select() to wait for incoming messages or
|
||||
// incoming SIGCHLD messages, along with passing an appropriate timeout to
|
||||
// select() to wake things up as necessary.
|
||||
//
|
||||
// The ordering of the following statements is also very purposeful. First,
|
||||
// we must be guaranteed that the helper thread is booted and available to
|
||||
// receive SIGCHLD signals, and then we must also ensure that we do a
|
||||
// nonblocking waitpid() at least once before we go ask the sigchld helper.
|
||||
// This prevents the race where the child exits, we boot the helper, and
|
||||
// then we ask for the child's exit status (never seeing a sigchld).
|
||||
//
|
||||
// The actual communication between the helper thread and this thread is
|
||||
// quite simple, just a channel moving data around.
|
||||
|
||||
unsafe { HELPER.boot(register_sigchld, waitpid_helper) }
|
||||
|
||||
match waitpid_nowait(pid) {
|
||||
Some(ret) => return Ok(ret),
|
||||
None => {}
|
||||
}
|
||||
|
||||
let (tx, rx) = channel();
|
||||
unsafe { HELPER.send(NewChild(pid, tx, deadline)); }
|
||||
return match rx.recv_opt() {
|
||||
Ok(e) => Ok(e),
|
||||
Err(()) => Err(util::timeout("wait timed out")),
|
||||
};
|
||||
|
||||
// Register a new SIGCHLD handler, returning the reading half of the
|
||||
// self-pipe plus the old handler registered (return value of sigaction).
|
||||
fn register_sigchld() -> (libc::c_int, c::sigaction) {
|
||||
unsafe {
|
||||
let mut old: c::sigaction = mem::init();
|
||||
let mut new: c::sigaction = mem::init();
|
||||
new.sa_handler = sigchld_handler;
|
||||
new.sa_flags = c::SA_NOCLDSTOP;
|
||||
assert_eq!(c::sigaction(c::SIGCHLD, &new, &mut old), 0);
|
||||
|
||||
let mut pipes = [0, ..2];
|
||||
assert_eq!(libc::pipe(pipes.as_mut_ptr()), 0);
|
||||
util::set_nonblocking(pipes[0], true).unwrap();
|
||||
util::set_nonblocking(pipes[1], true).unwrap();
|
||||
WRITE_FD = pipes[1];
|
||||
(pipes[0], old)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper thread for processing SIGCHLD messages
|
||||
fn waitpid_helper(input: libc::c_int,
|
||||
messages: Receiver<Req>,
|
||||
(read_fd, old): (libc::c_int, c::sigaction)) {
|
||||
util::set_nonblocking(input, true).unwrap();
|
||||
let mut set: c::fd_set = unsafe { mem::init() };
|
||||
let mut tv: libc::timeval;
|
||||
let mut active = Vec::<(libc::pid_t, Sender<p::ProcessExit>, u64)>::new();
|
||||
let max = cmp::max(input, read_fd) + 1;
|
||||
|
||||
'outer: loop {
|
||||
// Figure out the timeout of our syscall-to-happen. If we're waiting
|
||||
// for some processes, then they'll have a timeout, otherwise we
|
||||
// wait indefinitely for a message to arrive.
|
||||
//
|
||||
// FIXME: sure would be nice to not have to scan the entire array
|
||||
let min = active.iter().map(|a| *a.ref2()).enumerate().min_by(|p| {
|
||||
p.val1()
|
||||
});
|
||||
let (p, idx) = match min {
|
||||
Some((idx, deadline)) => {
|
||||
let now = ::io::timer::now();
|
||||
let ms = if now < deadline {deadline - now} else {0};
|
||||
tv = util::ms_to_timeval(ms);
|
||||
(&tv as *_, idx)
|
||||
}
|
||||
None => (ptr::null(), -1),
|
||||
};
|
||||
|
||||
// Wait for something to happen
|
||||
c::fd_set(&mut set, input);
|
||||
c::fd_set(&mut set, read_fd);
|
||||
match unsafe { c::select(max, &set, ptr::null(), ptr::null(), p) } {
|
||||
// interrupted, retry
|
||||
-1 if os::errno() == libc::EINTR as int => continue,
|
||||
|
||||
// We read something, break out and process
|
||||
1 | 2 => {}
|
||||
|
||||
// Timeout, the pending request is removed
|
||||
0 => {
|
||||
drop(active.remove(idx));
|
||||
continue
|
||||
}
|
||||
|
||||
n => fail!("error in select {} ({})", os::errno(), n),
|
||||
}
|
||||
|
||||
// Process any pending messages
|
||||
if drain(input) {
|
||||
loop {
|
||||
match messages.try_recv() {
|
||||
Ok(NewChild(pid, tx, deadline)) => {
|
||||
active.push((pid, tx, deadline));
|
||||
}
|
||||
Err(comm::Disconnected) => {
|
||||
assert!(active.len() == 0);
|
||||
break 'outer;
|
||||
}
|
||||
Err(comm::Empty) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If a child exited (somehow received SIGCHLD), then poll all
|
||||
// children to see if any of them exited.
|
||||
//
|
||||
// We also attempt to be responsible netizens when dealing with
|
||||
// SIGCHLD by invoking any previous SIGCHLD handler instead of just
|
||||
// ignoring any previous SIGCHLD handler. Note that we don't provide
|
||||
// a 1:1 mapping of our handler invocations to the previous handler
|
||||
// invocations because we drain the `read_fd` entirely. This is
|
||||
// probably OK because the kernel is already allowed to coalesce
|
||||
// simultaneous signals, we're just doing some extra coalescing.
|
||||
//
|
||||
// Another point of note is that this likely runs the signal handler
|
||||
// on a different thread than the one that received the signal. I
|
||||
// *think* this is ok at this time.
|
||||
//
|
||||
// The main reason for doing this is to allow stdtest to run native
|
||||
// tests as well. Both libgreen and libnative are running around
|
||||
// with process timeouts, but libgreen should get there first
|
||||
// (currently libuv doesn't handle old signal handlers).
|
||||
if drain(read_fd) {
|
||||
let i: uint = unsafe { mem::transmute(old.sa_handler) };
|
||||
if i != 0 {
|
||||
assert!(old.sa_flags & c::SA_SIGINFO == 0);
|
||||
(old.sa_handler)(c::SIGCHLD);
|
||||
}
|
||||
|
||||
// FIXME: sure would be nice to not have to scan the entire
|
||||
// array...
|
||||
active.retain(|&(pid, ref tx, _)| {
|
||||
match waitpid_nowait(pid) {
|
||||
Some(msg) => { tx.send(msg); false }
|
||||
None => true,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Once this helper thread is done, we re-register the old sigchld
|
||||
// handler and close our intermediate file descriptors.
|
||||
unsafe {
|
||||
assert_eq!(c::sigaction(c::SIGCHLD, &old, ptr::mut_null()), 0);
|
||||
let _ = libc::close(read_fd);
|
||||
let _ = libc::close(WRITE_FD);
|
||||
WRITE_FD = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Drain all pending data from the file descriptor, returning if any data
|
||||
// could be drained. This requires that the file descriptor is in
|
||||
// nonblocking mode.
|
||||
fn drain(fd: libc::c_int) -> bool {
|
||||
let mut ret = false;
|
||||
loop {
|
||||
let mut buf = [0u8, ..1];
|
||||
match unsafe {
|
||||
libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void,
|
||||
buf.len() as libc::size_t)
|
||||
} {
|
||||
n if n > 0 => { ret = true; }
|
||||
0 => return true,
|
||||
-1 if util::wouldblock() => return ret,
|
||||
n => fail!("bad read {} ({})", os::last_os_error(), n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Signal handler for SIGCHLD signals, must be async-signal-safe!
|
||||
//
|
||||
// This function will write to the writing half of the "self pipe" to wake
|
||||
// up the helper thread if it's waiting. Note that this write must be
|
||||
// nonblocking because if it blocks and the reader is the thread we
|
||||
// interrupted, then we'll deadlock.
|
||||
//
|
||||
// When writing, if the write returns EWOULDBLOCK then we choose to ignore
|
||||
// it. At that point we're guaranteed that there's something in the pipe
|
||||
// which will wake up the other end at some point, so we just allow this
|
||||
// signal to be coalesced with the pending signals on the pipe.
|
||||
extern fn sigchld_handler(_signum: libc::c_int) {
|
||||
let mut msg = 1;
|
||||
match unsafe {
|
||||
libc::write(WRITE_FD, &mut msg as *mut _ as *libc::c_void, 1)
|
||||
} {
|
||||
1 => {}
|
||||
-1 if util::wouldblock() => {} // see above comments
|
||||
n => fail!("bad error on write fd: {} {}", n, os::errno()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -830,10 +1090,9 @@ fn waitpid_nowait(pid: pid_t) -> Option<p::ProcessExit> {
|
|||
|
||||
#[cfg(unix)]
|
||||
fn waitpid_os(pid: pid_t) -> Option<p::ProcessExit> {
|
||||
use libc::funcs::posix01::wait;
|
||||
let mut status = 0 as c_int;
|
||||
match retry(|| unsafe {
|
||||
wait::waitpid(pid, &mut status, libc::WNOHANG)
|
||||
c::waitpid(pid, &mut status, c::WNOHANG)
|
||||
}) {
|
||||
n if n == pid => Some(translate_status(status)),
|
||||
0 => None,
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <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.
|
||||
|
||||
//! Implementation of the helper thread for the timer module
|
||||
//!
|
||||
//! This module contains the management necessary for the timer worker thread.
|
||||
//! This thread is responsible for performing the send()s on channels for timers
|
||||
//! that are using channels instead of a blocking call.
|
||||
//!
|
||||
//! The timer thread is lazily initialized, and it's shut down via the
|
||||
//! `shutdown` function provided. It must be maintained as an invariant that
|
||||
//! `shutdown` is only called when the entire program is finished. No new timers
|
||||
//! can be created in the future and there must be no active timers at that
|
||||
//! time.
|
||||
|
||||
use std::mem;
|
||||
use std::rt::bookkeeping;
|
||||
use std::rt;
|
||||
use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
|
||||
|
||||
use io::timer::{Req, Shutdown};
|
||||
use task;
|
||||
|
||||
// You'll note that these variables are *not* protected by a lock. These
|
||||
// variables are initialized with a Once before any Timer is created and are
|
||||
// only torn down after everything else has exited. This means that these
|
||||
// variables are read-only during use (after initialization) and both of which
|
||||
// are safe to use concurrently.
|
||||
static mut HELPER_CHAN: *mut Sender<Req> = 0 as *mut Sender<Req>;
|
||||
static mut HELPER_SIGNAL: imp::signal = 0 as imp::signal;
|
||||
|
||||
static mut TIMER_HELPER_EXIT: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
||||
|
||||
pub fn boot(helper: fn(imp::signal, Receiver<Req>)) {
|
||||
static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
||||
static mut INITIALIZED: bool = false;
|
||||
|
||||
unsafe {
|
||||
let mut _guard = LOCK.lock();
|
||||
if !INITIALIZED {
|
||||
let (tx, rx) = channel();
|
||||
// promote this to a shared channel
|
||||
drop(tx.clone());
|
||||
HELPER_CHAN = mem::transmute(box tx);
|
||||
let (receive, send) = imp::new();
|
||||
HELPER_SIGNAL = send;
|
||||
|
||||
task::spawn(proc() {
|
||||
bookkeeping::decrement();
|
||||
helper(receive, rx);
|
||||
TIMER_HELPER_EXIT.lock().signal()
|
||||
});
|
||||
|
||||
rt::at_exit(proc() { shutdown() });
|
||||
INITIALIZED = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(req: Req) {
|
||||
unsafe {
|
||||
assert!(!HELPER_CHAN.is_null());
|
||||
(*HELPER_CHAN).send(req);
|
||||
imp::signal(HELPER_SIGNAL);
|
||||
}
|
||||
}
|
||||
|
||||
fn shutdown() {
|
||||
// Request a shutdown, and then wait for the task to exit
|
||||
unsafe {
|
||||
let guard = TIMER_HELPER_EXIT.lock();
|
||||
send(Shutdown);
|
||||
guard.wait();
|
||||
drop(guard);
|
||||
TIMER_HELPER_EXIT.destroy();
|
||||
}
|
||||
|
||||
|
||||
// Clean up after ther helper thread
|
||||
unsafe {
|
||||
imp::close(HELPER_SIGNAL);
|
||||
let _chan: Box<Sender<Req>> = mem::transmute(HELPER_CHAN);
|
||||
HELPER_CHAN = 0 as *mut Sender<Req>;
|
||||
HELPER_SIGNAL = 0 as imp::signal;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
mod imp {
|
||||
use libc;
|
||||
use std::os;
|
||||
|
||||
use io::file::FileDesc;
|
||||
|
||||
pub type signal = libc::c_int;
|
||||
|
||||
pub fn new() -> (signal, signal) {
|
||||
let pipe = os::pipe();
|
||||
(pipe.input, pipe.out)
|
||||
}
|
||||
|
||||
pub fn signal(fd: libc::c_int) {
|
||||
FileDesc::new(fd, false).inner_write([0]).unwrap();
|
||||
}
|
||||
|
||||
pub fn close(fd: libc::c_int) {
|
||||
let _fd = FileDesc::new(fd, true);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
mod imp {
|
||||
use libc::{BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle};
|
||||
use std::ptr;
|
||||
use libc;
|
||||
|
||||
pub type signal = HANDLE;
|
||||
|
||||
pub fn new() -> (HANDLE, HANDLE) {
|
||||
unsafe {
|
||||
let handle = CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
|
||||
ptr::null());
|
||||
(handle, handle)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signal(handle: HANDLE) {
|
||||
assert!(unsafe { SetEvent(handle) != 0 });
|
||||
}
|
||||
|
||||
pub fn close(handle: HANDLE) {
|
||||
assert!(unsafe { CloseHandle(handle) != 0 });
|
||||
}
|
||||
|
||||
extern "system" {
|
||||
fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
|
||||
bManualReset: BOOL,
|
||||
bInitialState: BOOL,
|
||||
lpName: LPCSTR) -> HANDLE;
|
||||
fn SetEvent(hEvent: HANDLE) -> BOOL;
|
||||
}
|
||||
}
|
|
@ -52,11 +52,14 @@ use std::os;
|
|||
use std::ptr;
|
||||
use std::rt::rtio;
|
||||
use std::sync::atomics;
|
||||
use std::comm;
|
||||
|
||||
use io::IoResult;
|
||||
use io::c;
|
||||
use io::file::FileDesc;
|
||||
use io::timer_helper;
|
||||
use io::helper_thread::Helper;
|
||||
|
||||
helper_init!(static mut HELPER: Helper<Req>)
|
||||
|
||||
pub struct Timer {
|
||||
id: uint,
|
||||
|
@ -79,9 +82,6 @@ pub enum Req {
|
|||
// Remove a timer based on its id and then send it back on the channel
|
||||
// provided
|
||||
RemoveTimer(uint, Sender<Box<Inner>>),
|
||||
|
||||
// Shut down the loop and then ACK this channel once it's shut down
|
||||
Shutdown,
|
||||
}
|
||||
|
||||
// returns the current time (in milliseconds)
|
||||
|
@ -93,7 +93,7 @@ pub fn now() -> u64 {
|
|||
}
|
||||
}
|
||||
|
||||
fn helper(input: libc::c_int, messages: Receiver<Req>) {
|
||||
fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
|
||||
let mut set: c::fd_set = unsafe { mem::init() };
|
||||
|
||||
let mut fd = FileDesc::new(input, true);
|
||||
|
@ -163,7 +163,7 @@ fn helper(input: libc::c_int, messages: Receiver<Req>) {
|
|||
1 => {
|
||||
loop {
|
||||
match messages.try_recv() {
|
||||
Ok(Shutdown) => {
|
||||
Err(comm::Disconnected) => {
|
||||
assert!(active.len() == 0);
|
||||
break 'outer;
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ fn helper(input: libc::c_int, messages: Receiver<Req>) {
|
|||
|
||||
impl Timer {
|
||||
pub fn new() -> IoResult<Timer> {
|
||||
timer_helper::boot(helper);
|
||||
unsafe { HELPER.boot(|| {}, helper); }
|
||||
|
||||
static mut ID: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
|
||||
let id = unsafe { ID.fetch_add(1, atomics::Relaxed) };
|
||||
|
@ -235,7 +235,7 @@ impl Timer {
|
|||
Some(i) => i,
|
||||
None => {
|
||||
let (tx, rx) = channel();
|
||||
timer_helper::send(RemoveTimer(self.id, tx));
|
||||
unsafe { HELPER.send(RemoveTimer(self.id, tx)); }
|
||||
rx.recv()
|
||||
}
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ impl rtio::RtioTimer for Timer {
|
|||
inner.interval = msecs;
|
||||
inner.target = now + msecs;
|
||||
|
||||
timer_helper::send(NewTimer(inner));
|
||||
unsafe { HELPER.send(NewTimer(inner)); }
|
||||
return rx;
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,7 @@ impl rtio::RtioTimer for Timer {
|
|||
inner.interval = msecs;
|
||||
inner.target = now + msecs;
|
||||
|
||||
timer_helper::send(NewTimer(inner));
|
||||
unsafe { HELPER.send(NewTimer(inner)); }
|
||||
return rx;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,13 @@
|
|||
use libc;
|
||||
use std::ptr;
|
||||
use std::rt::rtio;
|
||||
use std::comm;
|
||||
|
||||
use io::timer_helper;
|
||||
use io::helper_thread::Helper;
|
||||
use io::IoResult;
|
||||
|
||||
helper_init!(static mut HELPER: Helper<Req>)
|
||||
|
||||
pub struct Timer {
|
||||
obj: libc::HANDLE,
|
||||
on_worker: bool,
|
||||
|
@ -35,10 +38,9 @@ pub struct Timer {
|
|||
pub enum Req {
|
||||
NewTimer(libc::HANDLE, Sender<()>, bool),
|
||||
RemoveTimer(libc::HANDLE, Sender<()>),
|
||||
Shutdown,
|
||||
}
|
||||
|
||||
fn helper(input: libc::HANDLE, messages: Receiver<Req>) {
|
||||
fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
|
||||
let mut objs = vec![input];
|
||||
let mut chans = vec![];
|
||||
|
||||
|
@ -67,12 +69,12 @@ fn helper(input: libc::HANDLE, messages: Receiver<Req>) {
|
|||
None => {}
|
||||
}
|
||||
}
|
||||
Ok(Shutdown) => {
|
||||
Err(comm::Disconnected) => {
|
||||
assert_eq!(objs.len(), 1);
|
||||
assert_eq!(chans.len(), 0);
|
||||
break 'outer;
|
||||
}
|
||||
_ => break
|
||||
Err(..) => break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -102,7 +104,7 @@ pub fn now() -> u64 {
|
|||
|
||||
impl Timer {
|
||||
pub fn new() -> IoResult<Timer> {
|
||||
timer_helper::boot(helper);
|
||||
unsafe { HELPER.boot(|| {}, helper) }
|
||||
|
||||
let obj = unsafe {
|
||||
imp::CreateWaitableTimerA(ptr::mut_null(), 0, ptr::null())
|
||||
|
@ -124,7 +126,7 @@ impl Timer {
|
|||
if !self.on_worker { return }
|
||||
|
||||
let (tx, rx) = channel();
|
||||
timer_helper::send(RemoveTimer(self.obj, tx));
|
||||
unsafe { HELPER.send(RemoveTimer(self.obj, tx)) }
|
||||
rx.recv();
|
||||
|
||||
self.on_worker = false;
|
||||
|
@ -157,7 +159,7 @@ impl rtio::RtioTimer for Timer {
|
|||
ptr::mut_null(), 0)
|
||||
}, 1);
|
||||
|
||||
timer_helper::send(NewTimer(self.obj, tx, true));
|
||||
unsafe { HELPER.send(NewTimer(self.obj, tx, true)) }
|
||||
self.on_worker = true;
|
||||
return rx;
|
||||
}
|
||||
|
@ -173,7 +175,7 @@ impl rtio::RtioTimer for Timer {
|
|||
ptr::null(), ptr::mut_null(), 0)
|
||||
}, 1);
|
||||
|
||||
timer_helper::send(NewTimer(self.obj, tx, false));
|
||||
unsafe { HELPER.send(NewTimer(self.obj, tx, false)) }
|
||||
self.on_worker = true;
|
||||
|
||||
return rx;
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
// NB this crate explicitly does *not* allow glob imports, please seriously
|
||||
// consider whether they're needed before adding that feature here (the
|
||||
// answer is that you don't need them)
|
||||
#![feature(macro_rules)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ A `BigInt` is a combination of `BigUint` and `Sign`.
|
|||
use Integer;
|
||||
|
||||
use std::cmp;
|
||||
use std::default::Default;
|
||||
use std::fmt;
|
||||
use std::from_str::FromStr;
|
||||
use std::num::CheckedDiv;
|
||||
|
@ -112,6 +113,11 @@ impl TotalOrd for BigUint {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for BigUint {
|
||||
#[inline]
|
||||
fn default() -> BigUint { BigUint::new(Vec::new()) }
|
||||
}
|
||||
|
||||
impl fmt::Show for BigUint {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f.buf, "{}", self.to_str_radix(10))
|
||||
|
@ -830,6 +836,11 @@ impl TotalOrd for BigInt {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for BigInt {
|
||||
#[inline]
|
||||
fn default() -> BigInt { BigInt::new(Zero, Vec::new()) }
|
||||
}
|
||||
|
||||
impl fmt::Show for BigInt {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f.buf, "{}", self.to_str_radix(10))
|
||||
|
|
|
@ -54,8 +54,8 @@ fn run_ar(sess: &Session, args: &str, cwd: Option<&Path>,
|
|||
cwd: cwd.map(|a| &*a),
|
||||
.. ProcessConfig::new()
|
||||
}) {
|
||||
Ok(mut prog) => {
|
||||
let o = prog.wait_with_output();
|
||||
Ok(prog) => {
|
||||
let o = prog.wait_with_output().unwrap();
|
||||
if !o.status.success() {
|
||||
sess.err(format!("{} {} failed with: {}", ar, args.connect(" "),
|
||||
o.status));
|
||||
|
|
|
@ -100,6 +100,7 @@ impl<'a> fold::Folder for StandardLibraryInjector<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
// `extern crate` must be precede `use` items
|
||||
vis.push_all_move(krate.module.view_items.clone());
|
||||
let new_module = ast::Mod {
|
||||
view_items: vis,
|
||||
|
@ -130,8 +131,20 @@ impl<'a> fold::Folder for PreludeInjector<'a> {
|
|||
if !no_prelude(krate.attrs.as_slice()) {
|
||||
// only add `use std::prelude::*;` if there wasn't a
|
||||
// `#![no_implicit_prelude]` at the crate level.
|
||||
|
||||
let mut attrs = krate.attrs.clone();
|
||||
|
||||
// fold_mod() will insert glob path.
|
||||
let globs_attr = attr::mk_attr(attr::mk_list_item(
|
||||
InternedString::new("feature"),
|
||||
vec!(
|
||||
attr::mk_word_item(InternedString::new("globs")),
|
||||
)));
|
||||
attrs.push(globs_attr);
|
||||
|
||||
ast::Crate {
|
||||
module: self.fold_mod(&krate.module),
|
||||
attrs: attrs,
|
||||
..krate
|
||||
}
|
||||
} else {
|
||||
|
@ -175,11 +188,20 @@ impl<'a> fold::Folder for PreludeInjector<'a> {
|
|||
span: DUMMY_SP,
|
||||
};
|
||||
|
||||
let vis = (vec!(vi2)).append(module.view_items.as_slice());
|
||||
let (crates, uses) = module.view_items.partitioned(|x| {
|
||||
match x.node {
|
||||
ast::ViewItemExternCrate(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
|
||||
// add vi2 after any `extern crate` but before any `use`
|
||||
let mut view_items = crates;
|
||||
view_items.push(vi2);
|
||||
view_items.push_all_move(uses);
|
||||
|
||||
// FIXME #2543: Bad copy.
|
||||
let new_module = ast::Mod {
|
||||
view_items: vis,
|
||||
view_items: view_items,
|
||||
..(*module).clone()
|
||||
};
|
||||
fold::noop_fold_mod(&new_module, self)
|
||||
|
|
|
@ -398,8 +398,7 @@ pub mod llvm {
|
|||
pub fn LLVMIsPackedStruct(StructTy: TypeRef) -> Bool;
|
||||
|
||||
/* Operations on array, pointer, and vector types (sequence types) */
|
||||
pub fn LLVMArrayType(ElementType: TypeRef, ElementCount: c_uint)
|
||||
-> TypeRef;
|
||||
pub fn LLVMRustArrayType(ElementType: TypeRef, ElementCount: u64) -> TypeRef;
|
||||
pub fn LLVMPointerType(ElementType: TypeRef, AddressSpace: c_uint)
|
||||
-> TypeRef;
|
||||
pub fn LLVMVectorType(ElementType: TypeRef, ElementCount: c_uint)
|
||||
|
|
|
@ -148,6 +148,33 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
|
|||
}
|
||||
}
|
||||
}
|
||||
ExprBlock(ref block) => {
|
||||
// Check all statements in the block
|
||||
for stmt in block.stmts.iter() {
|
||||
let block_span_err = |span|
|
||||
v.tcx.sess.span_err(span,
|
||||
"blocks in constants are limited to \
|
||||
items and tail expressions");
|
||||
match stmt.node {
|
||||
StmtDecl(ref span, _) => {
|
||||
match span.node {
|
||||
DeclLocal(_) => block_span_err(span.span),
|
||||
|
||||
// Item statements are allowed
|
||||
DeclItem(_) => {}
|
||||
}
|
||||
}
|
||||
StmtExpr(ref expr, _) => block_span_err(expr.span),
|
||||
StmtSemi(ref semi, _) => block_span_err(semi.span),
|
||||
StmtMac(..) => v.tcx.sess.span_bug(e.span,
|
||||
"unexpanded statement macro in const?!")
|
||||
}
|
||||
}
|
||||
match block.expr {
|
||||
Some(ref expr) => check_expr(v, &**expr, true),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
ExprVstore(_, ExprVstoreMutSlice) |
|
||||
ExprVstore(_, ExprVstoreSlice) |
|
||||
ExprVec(_) |
|
||||
|
|
|
@ -239,7 +239,15 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@Pat]) -> useful {
|
|||
return not_useful
|
||||
}
|
||||
let real_pat = match m.iter().find(|r| r.get(0).id != 0) {
|
||||
Some(r) => *r.get(0), None => v[0]
|
||||
Some(r) => {
|
||||
match r.get(0).node {
|
||||
// An arm of the form `ref x @ sub_pat` has type
|
||||
// `sub_pat`, not `&sub_pat` as `x` itself does.
|
||||
PatIdent(BindByRef(_), _, Some(sub)) => sub,
|
||||
_ => *r.get(0)
|
||||
}
|
||||
}
|
||||
None => v[0]
|
||||
};
|
||||
let left_ty = if real_pat.id == 0 { ty::mk_nil() }
|
||||
else { ty::node_id_to_type(cx.tcx, real_pat.id) };
|
||||
|
@ -258,7 +266,7 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@Pat]) -> useful {
|
|||
val(const_bool(false)),
|
||||
0u, left_ty)
|
||||
}
|
||||
ref u => (*u).clone(),
|
||||
u => u,
|
||||
}
|
||||
}
|
||||
ty::ty_enum(eid, _) => {
|
||||
|
@ -266,7 +274,7 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@Pat]) -> useful {
|
|||
match is_useful_specialized(cx, m, v, variant(va.id),
|
||||
va.args.len(), left_ty) {
|
||||
not_useful => (),
|
||||
ref u => return (*u).clone(),
|
||||
u => return u,
|
||||
}
|
||||
}
|
||||
not_useful
|
||||
|
@ -288,7 +296,7 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@Pat]) -> useful {
|
|||
for n in iter::range(0u, max_len + 1) {
|
||||
match is_useful_specialized(cx, m, v, vec(n), n, left_ty) {
|
||||
not_useful => (),
|
||||
ref u => return (*u).clone(),
|
||||
u => return u,
|
||||
}
|
||||
}
|
||||
not_useful
|
||||
|
@ -304,21 +312,21 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@Pat]) -> useful {
|
|||
}
|
||||
}
|
||||
}
|
||||
Some(ref ctor) => {
|
||||
Some(ctor) => {
|
||||
match is_useful(cx,
|
||||
&m.iter().filter_map(|r| {
|
||||
default(cx, r.as_slice())
|
||||
}).collect::<matrix>(),
|
||||
v.tail()) {
|
||||
useful_ => useful(left_ty, (*ctor).clone()),
|
||||
ref u => (*u).clone(),
|
||||
useful_ => useful(left_ty, ctor),
|
||||
u => u,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(ref v0_ctor) => {
|
||||
let arity = ctor_arity(cx, v0_ctor, left_ty);
|
||||
is_useful_specialized(cx, m, v, (*v0_ctor).clone(), arity, left_ty)
|
||||
Some(v0_ctor) => {
|
||||
let arity = ctor_arity(cx, &v0_ctor, left_ty);
|
||||
is_useful_specialized(cx, m, v, v0_ctor, arity, left_ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -337,7 +345,7 @@ fn is_useful_specialized(cx: &MatchCheckCtxt,
|
|||
cx, &ms, specialize(cx, v, &ctor, arity, lty).unwrap().as_slice());
|
||||
match could_be_useful {
|
||||
useful_ => useful(lty, ctor),
|
||||
ref u => (*u).clone(),
|
||||
u => u,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,9 +416,9 @@ fn missing_ctor(cx: &MatchCheckCtxt,
|
|||
let mut found = Vec::new();
|
||||
for r in m.iter() {
|
||||
let r = pat_ctor_id(cx, *r.get(0));
|
||||
for id in r.iter() {
|
||||
if !found.contains(id) {
|
||||
found.push((*id).clone());
|
||||
for id in r.move_iter() {
|
||||
if !found.contains(&id) {
|
||||
found.push(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -812,30 +820,17 @@ fn specialize(cx: &MatchCheckCtxt,
|
|||
let num_elements = before.len() + after.len();
|
||||
if num_elements < arity && slice.is_some() {
|
||||
let mut result = Vec::new();
|
||||
for pat in before.iter() {
|
||||
result.push((*pat).clone());
|
||||
}
|
||||
for _ in iter::range(0, arity - num_elements) {
|
||||
result.push(wild())
|
||||
}
|
||||
for pat in after.iter() {
|
||||
result.push((*pat).clone());
|
||||
}
|
||||
for pat in r.tail().iter() {
|
||||
result.push((*pat).clone());
|
||||
}
|
||||
let wilds = Vec::from_elem(arity - num_elements, wild());
|
||||
result.push_all_move(before);
|
||||
result.push_all_move(wilds);
|
||||
result.push_all_move(after);
|
||||
result.push_all(r.tail());
|
||||
Some(result)
|
||||
} else if num_elements == arity {
|
||||
let mut result = Vec::new();
|
||||
for pat in before.iter() {
|
||||
result.push((*pat).clone());
|
||||
}
|
||||
for pat in after.iter() {
|
||||
result.push((*pat).clone());
|
||||
}
|
||||
for pat in r.tail().iter() {
|
||||
result.push((*pat).clone());
|
||||
}
|
||||
result.push_all_move(before);
|
||||
result.push_all_move(after);
|
||||
result.push_all(r.tail());
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -47,7 +47,6 @@ use std::rc::Rc;
|
|||
// fixed-size vectors and strings: [] and ""/_
|
||||
// vector and string slices: &[] and &""
|
||||
// tuples: (,)
|
||||
// records: {...}
|
||||
// enums: foo(...)
|
||||
// floating point literals and operators
|
||||
// & and * pointers
|
||||
|
@ -241,6 +240,13 @@ impl<'a> ConstEvalVisitor<'a> {
|
|||
|
||||
ast::ExprRepeat(..) => general_const,
|
||||
|
||||
ast::ExprBlock(ref block) => {
|
||||
match block.expr {
|
||||
Some(ref e) => self.classify(&**e),
|
||||
None => integral_const
|
||||
}
|
||||
}
|
||||
|
||||
_ => non_const
|
||||
};
|
||||
self.ccache.insert(did, cn);
|
||||
|
@ -479,6 +485,12 @@ pub fn eval_const_expr_partial<T: ty::ExprTyProvider>(tcx: &T, e: &Expr)
|
|||
// If we have a vstore, just keep going; it has to be a string
|
||||
ExprVstore(e, _) => eval_const_expr_partial(tcx, e),
|
||||
ExprParen(e) => eval_const_expr_partial(tcx, e),
|
||||
ExprBlock(ref block) => {
|
||||
match block.expr {
|
||||
Some(ref expr) => eval_const_expr_partial(tcx, &**expr),
|
||||
None => Ok(const_int(0i64))
|
||||
}
|
||||
}
|
||||
_ => Err("unsupported constant expr".to_strbuf())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ use middle::typeck::astconv::{ast_ty_to_ty, AstConv};
|
|||
use middle::typeck::infer;
|
||||
use middle::typeck;
|
||||
use util::ppaux::{ty_to_str};
|
||||
use util::nodemap::NodeSet;
|
||||
|
||||
use std::cmp;
|
||||
use collections::HashMap;
|
||||
|
@ -456,7 +457,10 @@ struct Context<'a> {
|
|||
lint_stack: Vec<(Lint, level, LintSource)>,
|
||||
|
||||
// id of the last visited negated expression
|
||||
negated_expr_id: ast::NodeId
|
||||
negated_expr_id: ast::NodeId,
|
||||
|
||||
// ids of structs/enums which have been checked for raw_pointer_deriving
|
||||
checked_raw_pointers: NodeSet,
|
||||
}
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
|
@ -1014,10 +1018,26 @@ impl<'a> Visitor<()> for RawPtrDerivingVisitor<'a> {
|
|||
fn visit_block(&mut self, _: &ast::Block, _: ()) {}
|
||||
}
|
||||
|
||||
fn check_raw_ptr_deriving(cx: &Context, item: &ast::Item) {
|
||||
if !attr::contains_name(item.attrs.as_slice(), "deriving") {
|
||||
fn check_raw_ptr_deriving(cx: &mut Context, item: &ast::Item) {
|
||||
if !attr::contains_name(item.attrs.as_slice(), "automatically_derived") {
|
||||
return
|
||||
}
|
||||
let did = match item.node {
|
||||
ast::ItemImpl(..) => {
|
||||
match ty::get(ty::node_id_to_type(cx.tcx, item.id)).sty {
|
||||
ty::ty_enum(did, _) => did,
|
||||
ty::ty_struct(did, _) => did,
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
if !ast_util::is_local(did) { return }
|
||||
let item = match cx.tcx.map.find(did.node) {
|
||||
Some(ast_map::NodeItem(item)) => item,
|
||||
_ => return,
|
||||
};
|
||||
if !cx.checked_raw_pointers.insert(item.id) { return }
|
||||
match item.node {
|
||||
ast::ItemStruct(..) | ast::ItemEnum(..) => {
|
||||
let mut visitor = RawPtrDerivingVisitor { cx: cx };
|
||||
|
@ -1848,7 +1868,8 @@ pub fn check_crate(tcx: &ty::ctxt,
|
|||
cur_struct_def_id: -1,
|
||||
is_doc_hidden: false,
|
||||
lint_stack: Vec::new(),
|
||||
negated_expr_id: -1
|
||||
negated_expr_id: -1,
|
||||
checked_raw_pointers: NodeSet::new(),
|
||||
};
|
||||
|
||||
// Install default lint levels, followed by the command line levels, and
|
||||
|
|
|
@ -1611,6 +1611,9 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
|
|||
}
|
||||
}
|
||||
ast::ItemStatic(_, m, expr) => {
|
||||
// Recurse on the expression to catch items in blocks
|
||||
let mut v = TransItemVisitor{ ccx: ccx };
|
||||
v.visit_expr(expr, ());
|
||||
consts::trans_const(ccx, m, item.id);
|
||||
// Do static_assert checking. It can't really be done much earlier
|
||||
// because we need to get the value of the bool out of LLVM
|
||||
|
|
|
@ -672,6 +672,12 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
|||
}
|
||||
}
|
||||
ast::ExprParen(e) => { const_expr(cx, e, is_local) }
|
||||
ast::ExprBlock(ref block) => {
|
||||
match block.expr {
|
||||
Some(ref expr) => const_expr(cx, &**expr, is_local),
|
||||
None => (C_nil(cx), true)
|
||||
}
|
||||
}
|
||||
_ => cx.sess().span_bug(e.span,
|
||||
"bad constant expression type in consts::const_expr")
|
||||
};
|
||||
|
|
|
@ -207,7 +207,7 @@ impl Type {
|
|||
}
|
||||
|
||||
pub fn array(ty: &Type, len: u64) -> Type {
|
||||
ty!(llvm::LLVMArrayType(ty.to_ref(), len as c_uint))
|
||||
ty!(llvm::LLVMRustArrayType(ty.to_ref(), len))
|
||||
}
|
||||
|
||||
pub fn vector(ty: &Type, len: u64) -> Type {
|
||||
|
|
|
@ -3554,6 +3554,12 @@ pub fn check_const_with_ty(fcx: &FnCtxt,
|
|||
_: Span,
|
||||
e: &ast::Expr,
|
||||
declty: ty::t) {
|
||||
// Gather locals in statics (because of block expressions).
|
||||
// This is technically uneccessary because locals in static items are forbidden,
|
||||
// but prevents type checking from blowing up before const checking can properly
|
||||
// emit a error.
|
||||
GatherLocalsVisitor { fcx: fcx }.visit_expr(e, ());
|
||||
|
||||
check_expr(fcx, e);
|
||||
let cty = fcx.expr_ty(e);
|
||||
demand::suptype(fcx, e.span, declty, cty);
|
||||
|
|
|
@ -90,7 +90,7 @@ fn get_base_type(inference_context: &InferCtxt,
|
|||
}
|
||||
}
|
||||
|
||||
fn type_is_defined_in_local_crate(original_type: t) -> bool {
|
||||
fn type_is_defined_in_local_crate(tcx: &ty::ctxt, original_type: t) -> bool {
|
||||
/*!
|
||||
*
|
||||
* For coherence, when we have `impl Trait for Type`, we need to
|
||||
|
@ -109,6 +109,14 @@ fn type_is_defined_in_local_crate(original_type: t) -> bool {
|
|||
found_nominal = true;
|
||||
}
|
||||
}
|
||||
ty_uniq(..) => {
|
||||
match tcx.lang_items.owned_box() {
|
||||
Some(did) if did.krate == ast::LOCAL_CRATE => {
|
||||
found_nominal = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
|
@ -194,11 +202,10 @@ impl<'a> visit::Visitor<()> for PrivilegedScopeVisitor<'a> {
|
|||
}
|
||||
}
|
||||
ItemImpl(_, Some(ref trait_ref), _, _) => {
|
||||
let tcx = self.cc.crate_context.tcx;
|
||||
// `for_ty` is `Type` in `impl Trait for Type`
|
||||
let for_ty =
|
||||
ty::node_id_to_type(self.cc.crate_context.tcx,
|
||||
item.id);
|
||||
if !type_is_defined_in_local_crate(for_ty) {
|
||||
let for_ty = ty::node_id_to_type(tcx, item.id);
|
||||
if !type_is_defined_in_local_crate(tcx, for_ty) {
|
||||
// This implementation is not in scope of its base
|
||||
// type. This still might be OK if the trait is
|
||||
// defined in the same crate.
|
||||
|
|
|
@ -355,18 +355,14 @@ pub fn ty_to_str(cx: &ctxt, typ: t) -> StrBuf {
|
|||
ty_bot => "!".to_strbuf(),
|
||||
ty_bool => "bool".to_strbuf(),
|
||||
ty_char => "char".to_strbuf(),
|
||||
ty_int(t) => ast_util::int_ty_to_str(t, None),
|
||||
ty_uint(t) => ast_util::uint_ty_to_str(t, None),
|
||||
ty_float(t) => ast_util::float_ty_to_str(t),
|
||||
ty_box(typ) => {
|
||||
("@".to_owned() + ty_to_str(cx, typ).as_slice()).to_strbuf()
|
||||
}
|
||||
ty_uniq(typ) => {
|
||||
("~".to_owned() + ty_to_str(cx, typ).as_slice()).to_strbuf()
|
||||
}
|
||||
ty_ptr(ref tm) => {
|
||||
("*".to_owned() + mt_to_str(cx, tm).as_slice()).to_strbuf()
|
||||
}
|
||||
ty_int(t) => ast_util::int_ty_to_str(t, None,
|
||||
ast_util::AutoSuffix).to_strbuf(),
|
||||
ty_uint(t) => ast_util::uint_ty_to_str(t, None,
|
||||
ast_util::AutoSuffix).to_strbuf(),
|
||||
ty_float(t) => ast_util::float_ty_to_str(t).to_strbuf(),
|
||||
ty_box(typ) => format_strbuf!("@{}", ty_to_str(cx, typ)),
|
||||
ty_uniq(typ) => format_strbuf!("~{}", ty_to_str(cx, typ)),
|
||||
ty_ptr(ref tm) => format_strbuf!("*{}", mt_to_str(cx, tm)),
|
||||
ty_rptr(r, ref tm) => {
|
||||
let mut buf = region_ptr_to_str(cx, r);
|
||||
buf.push_str(mt_to_str(cx, tm).as_slice());
|
||||
|
@ -374,7 +370,7 @@ pub fn ty_to_str(cx: &ctxt, typ: t) -> StrBuf {
|
|||
}
|
||||
ty_tup(ref elems) => {
|
||||
let strs: Vec<StrBuf> = elems.iter().map(|elem| ty_to_str(cx, *elem)).collect();
|
||||
("(".to_owned() + strs.connect(",") + ")").to_strbuf()
|
||||
format_strbuf!("({})", strs.connect(","))
|
||||
}
|
||||
ty_closure(ref f) => {
|
||||
closure_to_str(cx, *f)
|
||||
|
|
|
@ -26,6 +26,7 @@ use t = syntax::parse::token;
|
|||
|
||||
/// Highlights some source code, returning the HTML output.
|
||||
pub fn highlight(src: &str, class: Option<&str>) -> StrBuf {
|
||||
debug!("highlighting: ================\n{}\n==============", src);
|
||||
let sess = parse::new_parse_sess();
|
||||
let fm = parse::string_to_filemap(&sess,
|
||||
src.to_strbuf(),
|
||||
|
|
|
@ -149,6 +149,7 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
|
|||
let my_opaque: &MyOpaque = &*((*opaque).opaque as *MyOpaque);
|
||||
slice::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
|
||||
let text = str::from_utf8(text).unwrap();
|
||||
debug!("docblock: ==============\n{}\n=======", text);
|
||||
let mut lines = text.lines().filter(|l| {
|
||||
stripped_filtered_line(*l).is_none()
|
||||
});
|
||||
|
|
|
@ -19,7 +19,8 @@ use std::rt::task::BlockedTask;
|
|||
use homing::{HomingIO, HomeHandle};
|
||||
use pipe::PipeWatcher;
|
||||
use super::{UvHandle, UvError, uv_error_to_io_error,
|
||||
wait_until_woken_after, wakeup};
|
||||
wait_until_woken_after, wakeup, Loop};
|
||||
use timer::TimerWatcher;
|
||||
use uvio::UvIoFactory;
|
||||
use uvll;
|
||||
|
||||
|
@ -32,6 +33,16 @@ pub struct Process {
|
|||
|
||||
/// Collected from the exit_cb
|
||||
exit_status: Option<process::ProcessExit>,
|
||||
|
||||
/// Lazily initialized timeout timer
|
||||
timer: Option<Box<TimerWatcher>>,
|
||||
timeout_state: TimeoutState,
|
||||
}
|
||||
|
||||
enum TimeoutState {
|
||||
NoTimeout,
|
||||
TimeoutPending,
|
||||
TimeoutElapsed,
|
||||
}
|
||||
|
||||
impl Process {
|
||||
|
@ -92,6 +103,8 @@ impl Process {
|
|||
home: io_loop.make_handle(),
|
||||
to_wake: None,
|
||||
exit_status: None,
|
||||
timer: None,
|
||||
timeout_state: NoTimeout,
|
||||
};
|
||||
match unsafe {
|
||||
uvll::uv_spawn(io_loop.uv_loop(), handle, &options)
|
||||
|
@ -223,21 +236,71 @@ impl RtioProcess for Process {
|
|||
}
|
||||
}
|
||||
|
||||
fn wait(&mut self) -> process::ProcessExit {
|
||||
fn wait(&mut self) -> Result<process::ProcessExit, IoError> {
|
||||
// Make sure (on the home scheduler) that we have an exit status listed
|
||||
let _m = self.fire_homing_missile();
|
||||
match self.exit_status {
|
||||
Some(..) => {}
|
||||
None => {
|
||||
// If there's no exit code previously listed, then the
|
||||
// process's exit callback has yet to be invoked. We just
|
||||
// need to deschedule ourselves and wait to be reawoken.
|
||||
Some(status) => return Ok(status),
|
||||
None => {}
|
||||
}
|
||||
|
||||
// If there's no exit code previously listed, then the process's exit
|
||||
// callback has yet to be invoked. We just need to deschedule ourselves
|
||||
// and wait to be reawoken.
|
||||
match self.timeout_state {
|
||||
NoTimeout | TimeoutPending => {
|
||||
wait_until_woken_after(&mut self.to_wake, &self.uv_loop(), || {});
|
||||
assert!(self.exit_status.is_some());
|
||||
}
|
||||
TimeoutElapsed => {}
|
||||
}
|
||||
|
||||
// If there's still no exit status listed, then we timed out, and we
|
||||
// need to return.
|
||||
match self.exit_status {
|
||||
Some(status) => Ok(status),
|
||||
None => Err(uv_error_to_io_error(UvError(uvll::ECANCELED)))
|
||||
}
|
||||
}
|
||||
|
||||
self.exit_status.unwrap()
|
||||
fn set_timeout(&mut self, timeout: Option<u64>) {
|
||||
let _m = self.fire_homing_missile();
|
||||
self.timeout_state = NoTimeout;
|
||||
let ms = match timeout {
|
||||
Some(ms) => ms,
|
||||
None => {
|
||||
match self.timer {
|
||||
Some(ref mut timer) => timer.stop(),
|
||||
None => {}
|
||||
}
|
||||
return
|
||||
}
|
||||
};
|
||||
if self.timer.is_none() {
|
||||
let loop_ = Loop::wrap(unsafe {
|
||||
uvll::get_loop_for_uv_handle(self.uv_handle())
|
||||
});
|
||||
let mut timer = box TimerWatcher::new_home(&loop_, self.home().clone());
|
||||
unsafe {
|
||||
timer.set_data(self as *mut _ as *Process);
|
||||
}
|
||||
self.timer = Some(timer);
|
||||
}
|
||||
|
||||
let timer = self.timer.get_mut_ref();
|
||||
timer.stop();
|
||||
timer.start(timer_cb, ms, 0);
|
||||
self.timeout_state = TimeoutPending;
|
||||
|
||||
extern fn timer_cb(timer: *uvll::uv_timer_t) {
|
||||
let p: &mut Process = unsafe {
|
||||
&mut *(uvll::get_data_for_uv_handle(timer) as *mut Process)
|
||||
};
|
||||
p.timeout_state = TimeoutElapsed;
|
||||
match p.to_wake.take() {
|
||||
Some(task) => { let _t = task.wake().map(|t| t.reawaken()); }
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -207,6 +207,13 @@ mod tests {
|
|||
assert_eq!(FlagABC.bits(), 0x00000111);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_bits() {
|
||||
assert!(unsafe { Flags::from_bits(0x00000000) } == Flags::empty());
|
||||
assert!(unsafe { Flags::from_bits(0x00000001) } == FlagA);
|
||||
assert!(unsafe { Flags::from_bits(0x00000111) } == FlagABC);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_empty(){
|
||||
assert!(Flags::empty().is_empty());
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
//! Bindings for executing child processes
|
||||
|
||||
#![allow(experimental)]
|
||||
|
||||
use prelude::*;
|
||||
|
||||
use fmt;
|
||||
|
@ -50,7 +52,7 @@ use rt::rtio::{RtioProcess, IoFactory, LocalIo};
|
|||
/// };
|
||||
///
|
||||
/// let contents = child.stdout.get_mut_ref().read_to_end();
|
||||
/// assert!(child.wait().success());
|
||||
/// assert!(child.wait().unwrap().success());
|
||||
/// ```
|
||||
pub struct Process {
|
||||
handle: Box<RtioProcess:Send>,
|
||||
|
@ -284,7 +286,7 @@ impl Process {
|
|||
/// println!("stderr: {}", str::from_utf8_lossy(output.error.as_slice()));
|
||||
/// ```
|
||||
pub fn output(prog: &str, args: &[~str]) -> IoResult<ProcessOutput> {
|
||||
Process::new(prog, args).map(|mut p| p.wait_with_output())
|
||||
Process::new(prog, args).and_then(|p| p.wait_with_output())
|
||||
}
|
||||
|
||||
/// Executes a child process and collects its exit status. This will block
|
||||
|
@ -303,7 +305,7 @@ impl Process {
|
|||
/// println!("process exited with: {}", status);
|
||||
/// ```
|
||||
pub fn status(prog: &str, args: &[~str]) -> IoResult<ProcessExit> {
|
||||
Process::new(prog, args).map(|mut p| p.wait())
|
||||
Process::new(prog, args).and_then(|mut p| p.wait())
|
||||
}
|
||||
|
||||
/// Creates a new process with the specified configuration.
|
||||
|
@ -378,17 +380,72 @@ impl Process {
|
|||
/// after it has been called at least once.
|
||||
///
|
||||
/// The stdin handle to the child process will be closed before waiting.
|
||||
pub fn wait(&mut self) -> ProcessExit {
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function can fail if a timeout was previously specified via
|
||||
/// `set_timeout` and the timeout expires before the child exits.
|
||||
pub fn wait(&mut self) -> IoResult<ProcessExit> {
|
||||
drop(self.stdin.take());
|
||||
self.handle.wait()
|
||||
}
|
||||
|
||||
/// Sets a timeout, in milliseconds, for future calls to wait().
|
||||
///
|
||||
/// The argument specified is a relative distance into the future, in
|
||||
/// milliseconds, after which any call to wait() will return immediately
|
||||
/// with a timeout error, and all future calls to wait() will not block.
|
||||
///
|
||||
/// A value of `None` will clear any previous timeout, and a value of `Some`
|
||||
/// will override any previously set timeout.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![allow(experimental)]
|
||||
/// use std::io::process::{Process, ProcessExit};
|
||||
/// use std::io::IoResult;
|
||||
///
|
||||
/// fn run_gracefully(prog: &str) -> IoResult<ProcessExit> {
|
||||
/// let mut p = try!(Process::new("long-running-process", []));
|
||||
///
|
||||
/// // give the process 10 seconds to finish completely
|
||||
/// p.set_timeout(Some(10_000));
|
||||
/// match p.wait() {
|
||||
/// Ok(status) => return Ok(status),
|
||||
/// Err(..) => {}
|
||||
/// }
|
||||
///
|
||||
/// // Attempt to exit gracefully, but don't wait for it too long
|
||||
/// try!(p.signal_exit());
|
||||
/// p.set_timeout(Some(1_000));
|
||||
/// match p.wait() {
|
||||
/// Ok(status) => return Ok(status),
|
||||
/// Err(..) => {}
|
||||
/// }
|
||||
///
|
||||
/// // Well, we did our best, forcefully kill the process
|
||||
/// try!(p.signal_kill());
|
||||
/// p.set_timeout(None);
|
||||
/// p.wait()
|
||||
/// }
|
||||
/// ```
|
||||
#[experimental = "the type of the timeout is likely to change"]
|
||||
pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
|
||||
self.handle.set_timeout(timeout_ms)
|
||||
}
|
||||
|
||||
/// Simultaneously wait for the child to exit and collect all remaining
|
||||
/// output on the stdout/stderr handles, returning a `ProcessOutput`
|
||||
/// instance.
|
||||
///
|
||||
/// The stdin handle to the child is closed before waiting.
|
||||
pub fn wait_with_output(&mut self) -> ProcessOutput {
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function can fail for any of the same reasons that `wait()` can
|
||||
/// fail.
|
||||
pub fn wait_with_output(mut self) -> IoResult<ProcessOutput> {
|
||||
drop(self.stdin.take());
|
||||
fn read(stream: Option<io::PipeStream>) -> Receiver<IoResult<Vec<u8>>> {
|
||||
let (tx, rx) = channel();
|
||||
|
@ -404,11 +461,13 @@ impl Process {
|
|||
let stdout = read(self.stdout.take());
|
||||
let stderr = read(self.stderr.take());
|
||||
|
||||
let status = self.wait();
|
||||
let status = try!(self.wait());
|
||||
|
||||
ProcessOutput { status: status,
|
||||
Ok(ProcessOutput {
|
||||
status: status,
|
||||
output: stdout.recv().ok().unwrap_or(Vec::new()),
|
||||
error: stderr.recv().ok().unwrap_or(Vec::new()) }
|
||||
error: stderr.recv().ok().unwrap_or(Vec::new()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -421,7 +480,8 @@ impl Drop for Process {
|
|||
drop(self.stderr.take());
|
||||
drop(mem::replace(&mut self.extra_io, Vec::new()));
|
||||
|
||||
self.wait();
|
||||
self.set_timeout(None);
|
||||
let _ = self.wait().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,7 +501,7 @@ mod tests {
|
|||
let p = Process::configure(args);
|
||||
assert!(p.is_ok());
|
||||
let mut p = p.unwrap();
|
||||
assert!(p.wait().success());
|
||||
assert!(p.wait().unwrap().success());
|
||||
})
|
||||
|
||||
#[cfg(not(target_os="android"))]
|
||||
|
@ -465,7 +525,7 @@ mod tests {
|
|||
let p = Process::configure(args);
|
||||
assert!(p.is_ok());
|
||||
let mut p = p.unwrap();
|
||||
assert!(p.wait().matches_exit_status(1));
|
||||
assert!(p.wait().unwrap().matches_exit_status(1));
|
||||
drop(p.wait().clone());
|
||||
})
|
||||
|
||||
|
@ -479,7 +539,7 @@ mod tests {
|
|||
let p = Process::configure(args);
|
||||
assert!(p.is_ok());
|
||||
let mut p = p.unwrap();
|
||||
match p.wait() {
|
||||
match p.wait().unwrap() {
|
||||
process::ExitSignal(1) => {},
|
||||
result => fail!("not terminated by signal 1 (instead, {})", result),
|
||||
}
|
||||
|
@ -495,7 +555,7 @@ mod tests {
|
|||
let mut p = p.unwrap();
|
||||
assert!(p.stdout.is_some());
|
||||
let ret = read_all(p.stdout.get_mut_ref() as &mut Reader);
|
||||
assert!(p.wait().success());
|
||||
assert!(p.wait().unwrap().success());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -536,7 +596,7 @@ mod tests {
|
|||
p.stdin.get_mut_ref().write("foobar".as_bytes()).unwrap();
|
||||
drop(p.stdin.take());
|
||||
let out = read_all(p.stdout.get_mut_ref() as &mut Reader);
|
||||
assert!(p.wait().success());
|
||||
assert!(p.wait().unwrap().success());
|
||||
assert_eq!(out, "foobar\n".to_owned());
|
||||
})
|
||||
|
||||
|
@ -548,7 +608,7 @@ mod tests {
|
|||
.. ProcessConfig::new()
|
||||
};
|
||||
let mut p = Process::configure(args).unwrap();
|
||||
assert!(p.wait().success());
|
||||
assert!(p.wait().unwrap().success());
|
||||
})
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -572,7 +632,7 @@ mod tests {
|
|||
.. ProcessConfig::new()
|
||||
};
|
||||
let mut p = Process::configure(args).unwrap();
|
||||
assert!(p.wait().success());
|
||||
assert!(p.wait().unwrap().success());
|
||||
})
|
||||
|
||||
#[cfg(unix, not(target_os="android"))]
|
||||
|
@ -635,21 +695,21 @@ mod tests {
|
|||
#[cfg(not(target_os="android"))]
|
||||
iotest!(fn test_finish_once() {
|
||||
let mut prog = Process::new("false", []).unwrap();
|
||||
assert!(prog.wait().matches_exit_status(1));
|
||||
assert!(prog.wait().unwrap().matches_exit_status(1));
|
||||
})
|
||||
|
||||
#[cfg(not(target_os="android"))]
|
||||
iotest!(fn test_finish_twice() {
|
||||
let mut prog = Process::new("false", []).unwrap();
|
||||
assert!(prog.wait().matches_exit_status(1));
|
||||
assert!(prog.wait().matches_exit_status(1));
|
||||
assert!(prog.wait().unwrap().matches_exit_status(1));
|
||||
assert!(prog.wait().unwrap().matches_exit_status(1));
|
||||
})
|
||||
|
||||
#[cfg(not(target_os="android"))]
|
||||
iotest!(fn test_wait_with_output_once() {
|
||||
|
||||
let mut prog = Process::new("echo", ["hello".to_owned()]).unwrap();
|
||||
let ProcessOutput {status, output, error} = prog.wait_with_output();
|
||||
let prog = Process::new("echo", ["hello".to_owned()]).unwrap();
|
||||
let ProcessOutput {status, output, error} = prog.wait_with_output().unwrap();
|
||||
let output_str = str::from_utf8(output.as_slice()).unwrap();
|
||||
|
||||
assert!(status.success());
|
||||
|
@ -660,30 +720,6 @@ mod tests {
|
|||
}
|
||||
})
|
||||
|
||||
#[cfg(not(target_os="android"))]
|
||||
iotest!(fn test_wait_with_output_twice() {
|
||||
let mut prog = Process::new("echo", ["hello".to_owned()]).unwrap();
|
||||
let ProcessOutput {status, output, error} = prog.wait_with_output();
|
||||
|
||||
let output_str = str::from_utf8(output.as_slice()).unwrap();
|
||||
|
||||
assert!(status.success());
|
||||
assert_eq!(output_str.trim().to_owned(), "hello".to_owned());
|
||||
// FIXME #7224
|
||||
if !running_on_valgrind() {
|
||||
assert_eq!(error, Vec::new());
|
||||
}
|
||||
|
||||
let ProcessOutput {status, output, error} = prog.wait_with_output();
|
||||
|
||||
assert!(status.success());
|
||||
assert_eq!(output, Vec::new());
|
||||
// FIXME #7224
|
||||
if !running_on_valgrind() {
|
||||
assert_eq!(error, Vec::new());
|
||||
}
|
||||
})
|
||||
|
||||
#[cfg(unix,not(target_os="android"))]
|
||||
pub fn run_pwd(dir: Option<&Path>) -> Process {
|
||||
Process::configure(ProcessConfig {
|
||||
|
@ -714,9 +750,10 @@ mod tests {
|
|||
|
||||
iotest!(fn test_keep_current_working_dir() {
|
||||
use os;
|
||||
let mut prog = run_pwd(None);
|
||||
let prog = run_pwd(None);
|
||||
|
||||
let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
|
||||
let output = str::from_utf8(prog.wait_with_output().unwrap()
|
||||
.output.as_slice()).unwrap().to_owned();
|
||||
let parent_dir = os::getcwd();
|
||||
let child_dir = Path::new(output.trim());
|
||||
|
||||
|
@ -732,9 +769,10 @@ mod tests {
|
|||
// test changing to the parent of os::getcwd() because we know
|
||||
// the path exists (and os::getcwd() is not expected to be root)
|
||||
let parent_dir = os::getcwd().dir_path();
|
||||
let mut prog = run_pwd(Some(&parent_dir));
|
||||
let prog = run_pwd(Some(&parent_dir));
|
||||
|
||||
let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
|
||||
let output = str::from_utf8(prog.wait_with_output().unwrap()
|
||||
.output.as_slice()).unwrap().to_owned();
|
||||
let child_dir = Path::new(output.trim());
|
||||
|
||||
let parent_stat = parent_dir.stat().unwrap();
|
||||
|
@ -777,8 +815,9 @@ mod tests {
|
|||
use os;
|
||||
if running_on_valgrind() { return; }
|
||||
|
||||
let mut prog = run_env(None);
|
||||
let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
|
||||
let prog = run_env(None);
|
||||
let output = str::from_utf8(prog.wait_with_output().unwrap()
|
||||
.output.as_slice()).unwrap().to_owned();
|
||||
|
||||
let r = os::env();
|
||||
for &(ref k, ref v) in r.iter() {
|
||||
|
@ -791,8 +830,10 @@ mod tests {
|
|||
use os;
|
||||
if running_on_valgrind() { return; }
|
||||
|
||||
let mut prog = run_env(None);
|
||||
let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
|
||||
let prog = run_env(None);
|
||||
let output = str::from_utf8(prog.wait_with_output()
|
||||
.unwrap().output.as_slice())
|
||||
.unwrap().to_owned();
|
||||
|
||||
let r = os::env();
|
||||
for &(ref k, ref v) in r.iter() {
|
||||
|
@ -807,8 +848,8 @@ mod tests {
|
|||
iotest!(fn test_add_to_env() {
|
||||
let new_env = box [("RUN_TEST_NEW_ENV".to_owned(), "123".to_owned())];
|
||||
|
||||
let mut prog = run_env(Some(new_env));
|
||||
let result = prog.wait_with_output();
|
||||
let prog = run_env(Some(new_env));
|
||||
let result = prog.wait_with_output().unwrap();
|
||||
let output = str::from_utf8_lossy(result.output.as_slice()).into_owned();
|
||||
|
||||
assert!(output.contains("RUN_TEST_NEW_ENV=123"),
|
||||
|
@ -830,14 +871,14 @@ mod tests {
|
|||
iotest!(fn test_kill() {
|
||||
let mut p = sleeper();
|
||||
Process::kill(p.id(), PleaseExitSignal).unwrap();
|
||||
assert!(!p.wait().success());
|
||||
assert!(!p.wait().unwrap().success());
|
||||
})
|
||||
|
||||
iotest!(fn test_exists() {
|
||||
let mut p = sleeper();
|
||||
assert!(Process::kill(p.id(), 0).is_ok());
|
||||
p.signal_kill().unwrap();
|
||||
assert!(!p.wait().success());
|
||||
assert!(!p.wait().unwrap().success());
|
||||
})
|
||||
|
||||
iotest!(fn test_zero() {
|
||||
|
@ -845,11 +886,42 @@ mod tests {
|
|||
p.signal_kill().unwrap();
|
||||
for _ in range(0, 20) {
|
||||
if p.signal(0).is_err() {
|
||||
assert!(!p.wait().success());
|
||||
assert!(!p.wait().unwrap().success());
|
||||
return
|
||||
}
|
||||
timer::sleep(100);
|
||||
}
|
||||
fail!("never saw the child go away");
|
||||
})
|
||||
|
||||
iotest!(fn wait_timeout() {
|
||||
let mut p = sleeper();
|
||||
p.set_timeout(Some(10));
|
||||
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
|
||||
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
|
||||
p.signal_kill().unwrap();
|
||||
p.set_timeout(None);
|
||||
assert!(p.wait().is_ok());
|
||||
})
|
||||
|
||||
iotest!(fn wait_timeout2() {
|
||||
let (tx, rx) = channel();
|
||||
let tx2 = tx.clone();
|
||||
spawn(proc() {
|
||||
let mut p = sleeper();
|
||||
p.set_timeout(Some(10));
|
||||
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
|
||||
p.signal_kill().unwrap();
|
||||
tx.send(());
|
||||
});
|
||||
spawn(proc() {
|
||||
let mut p = sleeper();
|
||||
p.set_timeout(Some(10));
|
||||
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
|
||||
p.signal_kill().unwrap();
|
||||
tx2.send(());
|
||||
});
|
||||
rx.recv();
|
||||
rx.recv();
|
||||
})
|
||||
}
|
||||
|
|
|
@ -133,14 +133,16 @@ extern crate core;
|
|||
#[cfg(test)] pub use ops = realstd::ops;
|
||||
#[cfg(test)] pub use cmp = realstd::cmp;
|
||||
#[cfg(test)] pub use ty = realstd::ty;
|
||||
#[cfg(test)] pub use owned = realstd::owned;
|
||||
#[cfg(not(stage0), test)] pub use owned = realstd::owned;
|
||||
|
||||
#[cfg(not(test))] pub use cmp = core::cmp;
|
||||
#[cfg(not(test))] pub use kinds = core::kinds;
|
||||
#[cfg(not(test))] pub use ops = core::ops;
|
||||
#[cfg(not(test))] pub use owned = core::owned;
|
||||
#[cfg(not(test))] pub use ty = core::ty;
|
||||
|
||||
#[cfg(stage0, test)] pub use owned = realstd::owned;
|
||||
#[cfg(stage0, not(test))] pub use owned = core::owned;
|
||||
|
||||
pub use core::any;
|
||||
pub use core::bool;
|
||||
pub use core::cell;
|
||||
|
@ -207,6 +209,8 @@ pub mod ascii;
|
|||
|
||||
pub mod rc;
|
||||
pub mod gc;
|
||||
#[cfg(not(stage0), not(test))]
|
||||
pub mod owned;
|
||||
|
||||
/* Common traits */
|
||||
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <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.
|
||||
|
||||
//! Operations on unique pointer types
|
||||
|
||||
use any::{Any, AnyRefExt};
|
||||
use clone::Clone;
|
||||
use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering};
|
||||
use default::Default;
|
||||
use intrinsics;
|
||||
use mem;
|
||||
use raw::TraitObject;
|
||||
use result::{Ok, Err, 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.
|
||||
///
|
||||
/// The following two examples are equivalent:
|
||||
///
|
||||
/// let foo = box(HEAP) Bar::new(...);
|
||||
/// let foo = box Bar::new(...);
|
||||
#[lang="exchange_heap"]
|
||||
pub static HEAP: () = ();
|
||||
|
||||
/// A type that represents a uniquely-owned value.
|
||||
#[lang="owned_box"]
|
||||
pub struct Box<T>(*T);
|
||||
|
||||
impl<T: Default> Default for Box<T> {
|
||||
fn default() -> Box<T> { box Default::default() }
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for Box<T> {
|
||||
/// Return a copy of the owned box.
|
||||
#[inline]
|
||||
fn clone(&self) -> Box<T> { box {(**self).clone()} }
|
||||
|
||||
/// Perform copy-assignment from `source` by reusing the existing allocation.
|
||||
#[inline]
|
||||
fn clone_from(&mut self, source: &Box<T>) {
|
||||
(**self).clone_from(&(**source));
|
||||
}
|
||||
}
|
||||
|
||||
// box pointers
|
||||
impl<T:Eq> Eq for Box<T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Box<T>) -> bool { *(*self) == *(*other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &Box<T>) -> bool { *(*self) != *(*other) }
|
||||
}
|
||||
impl<T:Ord> Ord for Box<T> {
|
||||
#[inline]
|
||||
fn lt(&self, other: &Box<T>) -> bool { *(*self) < *(*other) }
|
||||
#[inline]
|
||||
fn le(&self, other: &Box<T>) -> bool { *(*self) <= *(*other) }
|
||||
#[inline]
|
||||
fn ge(&self, other: &Box<T>) -> bool { *(*self) >= *(*other) }
|
||||
#[inline]
|
||||
fn gt(&self, other: &Box<T>) -> bool { *(*self) > *(*other) }
|
||||
}
|
||||
impl<T: TotalOrd> TotalOrd for Box<T> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Box<T>) -> Ordering { (**self).cmp(*other) }
|
||||
}
|
||||
impl<T: TotalEq> TotalEq for Box<T> {}
|
||||
|
||||
/// Extension methods for an owning `Any` trait object
|
||||
pub trait AnyOwnExt {
|
||||
/// Returns the boxed value if it is of type `T`, or
|
||||
/// `Err(Self)` if it isn't.
|
||||
fn move<T: 'static>(self) -> Result<Box<T>, Self>;
|
||||
}
|
||||
|
||||
impl AnyOwnExt for Box<Any> {
|
||||
#[inline]
|
||||
fn move<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
|
||||
if self.is::<T>() {
|
||||
unsafe {
|
||||
// Get the raw representation of the trait object
|
||||
let to: TraitObject =
|
||||
*mem::transmute::<&Box<Any>, &TraitObject>(&self);
|
||||
|
||||
// Prevent destructor on self being run
|
||||
intrinsics::forget(self);
|
||||
|
||||
// Extract the data pointer
|
||||
Ok(mem::transmute(to.data))
|
||||
}
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -275,7 +275,8 @@ pub trait RtioFileStream {
|
|||
pub trait RtioProcess {
|
||||
fn id(&self) -> libc::pid_t;
|
||||
fn kill(&mut self, signal: int) -> IoResult<()>;
|
||||
fn wait(&mut self) -> ProcessExit;
|
||||
fn wait(&mut self) -> IoResult<ProcessExit>;
|
||||
fn set_timeout(&mut self, timeout: Option<u64>);
|
||||
}
|
||||
|
||||
pub trait RtioPipe {
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
//! local storage, and logging. Even a 'freestanding' Rust would likely want
|
||||
//! to implement this.
|
||||
|
||||
use any::AnyOwnExt;
|
||||
use cleanup;
|
||||
use clone::Clone;
|
||||
use comm::Sender;
|
||||
|
@ -24,7 +23,7 @@ use local_data;
|
|||
use mem;
|
||||
use ops::Drop;
|
||||
use option::{Option, Some, None};
|
||||
use owned::Box;
|
||||
use owned::{AnyOwnExt, Box};
|
||||
use prelude::drop;
|
||||
use result::{Result, Ok, Err};
|
||||
use rt::Runtime;
|
||||
|
|
|
@ -228,25 +228,25 @@ fn canonical_sort(comb: &mut [(char, u8)]) {
|
|||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
enum NormalizationForm {
|
||||
NFD,
|
||||
NFKD
|
||||
enum DecompositionType {
|
||||
Canonical,
|
||||
Compatible
|
||||
}
|
||||
|
||||
/// External iterator for a string's normalization's characters.
|
||||
/// External iterator for a string's decomposition's characters.
|
||||
/// Use with the `std::iter` module.
|
||||
#[deriving(Clone)]
|
||||
pub struct Normalizations<'a> {
|
||||
kind: NormalizationForm,
|
||||
pub struct Decompositions<'a> {
|
||||
kind: DecompositionType,
|
||||
iter: Chars<'a>,
|
||||
buffer: Vec<(char, u8)>,
|
||||
sorted: bool
|
||||
}
|
||||
|
||||
impl<'a> Iterator<char> for Normalizations<'a> {
|
||||
impl<'a> Iterator<char> for Decompositions<'a> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<char> {
|
||||
use unicode::decompose::canonical_combining_class;
|
||||
use unicode::normalization::canonical_combining_class;
|
||||
|
||||
match self.buffer.as_slice().head() {
|
||||
Some(&(c, 0)) => {
|
||||
|
@ -262,8 +262,8 @@ impl<'a> Iterator<char> for Normalizations<'a> {
|
|||
}
|
||||
|
||||
let decomposer = match self.kind {
|
||||
NFD => char::decompose_canonical,
|
||||
NFKD => char::decompose_compatible
|
||||
Canonical => char::decompose_canonical,
|
||||
Compatible => char::decompose_compatible
|
||||
};
|
||||
|
||||
if !self.sorted {
|
||||
|
@ -887,24 +887,24 @@ pub trait StrAllocating: Str {
|
|||
/// An Iterator over the string in Unicode Normalization Form D
|
||||
/// (canonical decomposition).
|
||||
#[inline]
|
||||
fn nfd_chars<'a>(&'a self) -> Normalizations<'a> {
|
||||
Normalizations {
|
||||
fn nfd_chars<'a>(&'a self) -> Decompositions<'a> {
|
||||
Decompositions {
|
||||
iter: self.as_slice().chars(),
|
||||
buffer: Vec::new(),
|
||||
sorted: false,
|
||||
kind: NFD
|
||||
kind: Canonical
|
||||
}
|
||||
}
|
||||
|
||||
/// An Iterator over the string in Unicode Normalization Form KD
|
||||
/// (compatibility decomposition).
|
||||
#[inline]
|
||||
fn nfkd_chars<'a>(&'a self) -> Normalizations<'a> {
|
||||
Normalizations {
|
||||
fn nfkd_chars<'a>(&'a self) -> Decompositions<'a> {
|
||||
Decompositions {
|
||||
iter: self.as_slice().chars(),
|
||||
buffer: Vec::new(),
|
||||
sorted: false,
|
||||
kind: NFKD
|
||||
kind: Compatible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,10 +47,11 @@ use rt::local::Local;
|
|||
use rt::task::Task;
|
||||
use str::{Str, SendStr, IntoMaybeOwned};
|
||||
|
||||
#[cfg(test)] use any::{AnyOwnExt, AnyRefExt};
|
||||
#[cfg(test)] use any::AnyRefExt;
|
||||
#[cfg(test)] use owned::AnyOwnExt;
|
||||
#[cfg(test)] use realstd::result::ResultUnwrap;
|
||||
#[cfg(test)] use result;
|
||||
#[cfg(test)] use str::StrAllocating;
|
||||
#[cfg(test)] use realstd::result::ResultUnwrap;
|
||||
|
||||
/// Indicates the manner in which a task exited.
|
||||
///
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
@ -8,11 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// The following code was generated by "src/etc/unicode.py"
|
||||
// NOTE: The following code was generated by "src/etc/unicode.py", do not edit directly
|
||||
|
||||
#![allow(missing_doc, non_uppercase_statics)]
|
||||
|
||||
pub mod decompose {
|
||||
pub mod normalization {
|
||||
use option::{Some, None};
|
||||
use slice::ImmutableVector;
|
||||
|
||||
|
|
|
@ -711,7 +711,8 @@ pub enum IntTy {
|
|||
|
||||
impl fmt::Show for IntTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f.buf, "{}", ast_util::int_ty_to_str(*self, None))
|
||||
write!(f.buf, "{}",
|
||||
ast_util::int_ty_to_str(*self, None, ast_util::AutoSuffix))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,7 +727,8 @@ pub enum UintTy {
|
|||
|
||||
impl fmt::Show for UintTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f.buf, "{}", ast_util::uint_ty_to_str(*self, None))
|
||||
write!(f.buf, "{}",
|
||||
ast_util::uint_ty_to_str(*self, None, ast_util::AutoSuffix))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,11 +132,19 @@ pub fn is_path(e: @Expr) -> bool {
|
|||
return match e.node { ExprPath(_) => true, _ => false };
|
||||
}
|
||||
|
||||
pub enum SuffixMode {
|
||||
ForceSuffix,
|
||||
AutoSuffix,
|
||||
}
|
||||
|
||||
// Get a string representation of a signed int type, with its value.
|
||||
// We want to avoid "45int" and "-3int" in favor of "45" and "-3"
|
||||
pub fn int_ty_to_str(t: IntTy, val: Option<i64>) -> StrBuf {
|
||||
pub fn int_ty_to_str(t: IntTy, val: Option<i64>, mode: SuffixMode) -> StrBuf {
|
||||
let s = match t {
|
||||
TyI if val.is_some() => "",
|
||||
TyI if val.is_some() => match mode {
|
||||
AutoSuffix => "",
|
||||
ForceSuffix => "i",
|
||||
},
|
||||
TyI => "int",
|
||||
TyI8 => "i8",
|
||||
TyI16 => "i16",
|
||||
|
@ -145,7 +153,10 @@ pub fn int_ty_to_str(t: IntTy, val: Option<i64>) -> StrBuf {
|
|||
};
|
||||
|
||||
match val {
|
||||
Some(n) => format!("{}{}", n, s).to_strbuf(),
|
||||
// cast to a u64 so we can correctly print INT64_MIN. All integral types
|
||||
// are parsed as u64, so we wouldn't want to print an extra negative
|
||||
// sign.
|
||||
Some(n) => format!("{}{}", n as u64, s).to_strbuf(),
|
||||
None => s.to_strbuf()
|
||||
}
|
||||
}
|
||||
|
@ -161,9 +172,12 @@ pub fn int_ty_max(t: IntTy) -> u64 {
|
|||
|
||||
// Get a string representation of an unsigned int type, with its value.
|
||||
// We want to avoid "42uint" in favor of "42u"
|
||||
pub fn uint_ty_to_str(t: UintTy, val: Option<u64>) -> StrBuf {
|
||||
pub fn uint_ty_to_str(t: UintTy, val: Option<u64>, mode: SuffixMode) -> StrBuf {
|
||||
let s = match t {
|
||||
TyU if val.is_some() => "u",
|
||||
TyU if val.is_some() => match mode {
|
||||
AutoSuffix => "",
|
||||
ForceSuffix => "u",
|
||||
},
|
||||
TyU => "uint",
|
||||
TyU8 => "u8",
|
||||
TyU16 => "u16",
|
||||
|
|
|
@ -182,6 +182,7 @@ use std::cell::RefCell;
|
|||
use ast;
|
||||
use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
|
||||
use ast_util;
|
||||
use attr::AttrMetaMethods;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::build::AstBuilder;
|
||||
use codemap;
|
||||
|
@ -330,21 +331,34 @@ impl<'a> TraitDef<'a> {
|
|||
_mitem: @ast::MetaItem,
|
||||
item: @ast::Item,
|
||||
push: |@ast::Item|) {
|
||||
match item.node {
|
||||
let newitem = match item.node {
|
||||
ast::ItemStruct(struct_def, ref generics) => {
|
||||
push(self.expand_struct_def(cx,
|
||||
self.expand_struct_def(cx,
|
||||
struct_def,
|
||||
item.ident,
|
||||
generics));
|
||||
generics)
|
||||
}
|
||||
ast::ItemEnum(ref enum_def, ref generics) => {
|
||||
push(self.expand_enum_def(cx,
|
||||
self.expand_enum_def(cx,
|
||||
enum_def,
|
||||
item.ident,
|
||||
generics));
|
||||
generics)
|
||||
}
|
||||
_ => ()
|
||||
_ => return
|
||||
};
|
||||
// Keep the lint attributes of the previous item to control how the
|
||||
// generated implementations are linted
|
||||
let mut attrs = newitem.attrs.clone();
|
||||
attrs.extend(item.attrs.iter().filter(|a| {
|
||||
match a.name().get() {
|
||||
"allow" | "warn" | "deny" | "forbid" => true,
|
||||
_ => false,
|
||||
}
|
||||
}).map(|a| a.clone()));
|
||||
push(@ast::Item {
|
||||
attrs: attrs,
|
||||
..(*newitem).clone()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -156,7 +156,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
|
|||
// }
|
||||
// }
|
||||
|
||||
let local_ident = token::gensym_ident("i");
|
||||
let local_ident = token::gensym_ident("__i"); // FIXME #13573
|
||||
let next_ident = fld.cx.ident_of("next");
|
||||
let none_ident = fld.cx.ident_of("None");
|
||||
|
||||
|
@ -262,7 +262,8 @@ pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
|
|||
let it = expand_item_modifiers(it, fld);
|
||||
|
||||
let mut decorator_items = SmallVector::zero();
|
||||
for attr in it.attrs.iter().rev() {
|
||||
let mut new_attrs = Vec::new();
|
||||
for attr in it.attrs.iter() {
|
||||
let mname = attr.name();
|
||||
|
||||
match fld.extsbox.find(&intern(mname.get())) {
|
||||
|
@ -286,7 +287,7 @@ pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
|
|||
|
||||
fld.cx.bt_pop();
|
||||
}
|
||||
_ => {}
|
||||
_ => new_attrs.push((*attr).clone()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,14 +295,21 @@ pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
|
|||
ast::ItemMac(..) => expand_item_mac(it, fld),
|
||||
ast::ItemMod(_) | ast::ItemForeignMod(_) => {
|
||||
fld.cx.mod_push(it.ident);
|
||||
let macro_escape = contains_macro_escape(it.attrs.as_slice());
|
||||
let macro_escape = contains_macro_escape(new_attrs.as_slice());
|
||||
let result = with_exts_frame!(fld.extsbox,
|
||||
macro_escape,
|
||||
noop_fold_item(it, fld));
|
||||
fld.cx.mod_pop();
|
||||
result
|
||||
},
|
||||
_ => noop_fold_item(it, fld)
|
||||
_ => {
|
||||
let it = @ast::Item {
|
||||
attrs: new_attrs,
|
||||
..(*it).clone()
|
||||
|
||||
};
|
||||
noop_fold_item(it, fld)
|
||||
}
|
||||
};
|
||||
|
||||
new_items.push_all(decorator_items);
|
||||
|
|
|
@ -587,16 +587,64 @@ impl<'a> Parser<'a> {
|
|||
self.replace_token(token::BINOP(token::OR), lo, self.span.hi)
|
||||
}
|
||||
_ => {
|
||||
let token_str = self.this_token_to_str();
|
||||
let found_token =
|
||||
let found_token = self.this_token_to_str();
|
||||
let token_str =
|
||||
Parser::token_to_str(&token::BINOP(token::OR));
|
||||
self.fatal(format!("expected `{}`, found `{}`",
|
||||
found_token,
|
||||
token_str))
|
||||
token_str, found_token))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to consume a `<`. If `<<` is seen, replace it with a single
|
||||
// `<` and continue. If a `<` is not seen, return false.
|
||||
//
|
||||
// This is meant to be used when parsing generics on a path to get the
|
||||
// starting token. The `force` parameter is used to forcefully break up a
|
||||
// `<<` token. If `force` is false, then `<<` is only broken when a lifetime
|
||||
// shows up next. For example, consider the expression:
|
||||
//
|
||||
// foo as bar << test
|
||||
//
|
||||
// The parser needs to know if `bar <<` is the start of a generic path or if
|
||||
// it's a left-shift token. If `test` were a lifetime, then it's impossible
|
||||
// for the token to be a left-shift, but if it's not a lifetime, then it's
|
||||
// considered a left-shift.
|
||||
//
|
||||
// The reason for this is that the only current ambiguity with `<<` is when
|
||||
// parsing closure types:
|
||||
//
|
||||
// foo::<<'a> ||>();
|
||||
// impl Foo<<'a> ||>() { ... }
|
||||
fn eat_lt(&mut self, force: bool) -> bool {
|
||||
match self.token {
|
||||
token::LT => { self.bump(); true }
|
||||
token::BINOP(token::SHL) => {
|
||||
let next_lifetime = self.look_ahead(1, |t| match *t {
|
||||
token::LIFETIME(..) => true,
|
||||
_ => false,
|
||||
});
|
||||
if force || next_lifetime {
|
||||
let lo = self.span.lo + BytePos(1);
|
||||
self.replace_token(token::LT, lo, self.span.hi);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_lt(&mut self) {
|
||||
if !self.eat_lt(true) {
|
||||
let found_token = self.this_token_to_str();
|
||||
let token_str = Parser::token_to_str(&token::LT);
|
||||
self.fatal(format!("expected `{}`, found `{}`",
|
||||
token_str, found_token))
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a sequence bracketed by `|` and `|`, stopping before the `|`.
|
||||
fn parse_seq_to_before_or<T>(
|
||||
&mut self,
|
||||
|
@ -1500,7 +1548,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
// Parse the `<` before the lifetime and types, if applicable.
|
||||
let (any_lifetime_or_types, lifetimes, types) = {
|
||||
if mode != NoTypesAllowed && self.eat(&token::LT) {
|
||||
if mode != NoTypesAllowed && self.eat_lt(false) {
|
||||
let (lifetimes, types) =
|
||||
self.parse_generic_values_after_lt();
|
||||
(true, lifetimes, OwnedSlice::from_vec(types))
|
||||
|
@ -1948,7 +1996,7 @@ impl<'a> Parser<'a> {
|
|||
hi = self.span.hi;
|
||||
self.bump();
|
||||
let (_, tys) = if self.eat(&token::MOD_SEP) {
|
||||
self.expect(&token::LT);
|
||||
self.expect_lt();
|
||||
self.parse_generic_values_after_lt()
|
||||
} else {
|
||||
(Vec::new(), Vec::new())
|
||||
|
@ -2241,9 +2289,6 @@ impl<'a> Parser<'a> {
|
|||
ExprVec(..) if m == MutImmutable => {
|
||||
ExprVstore(e, ExprVstoreSlice)
|
||||
}
|
||||
ExprLit(lit) if lit_is_str(lit) && m == MutImmutable => {
|
||||
ExprVstore(e, ExprVstoreSlice)
|
||||
}
|
||||
ExprVec(..) if m == MutMutable => {
|
||||
ExprVstore(e, ExprVstoreMutSlice)
|
||||
}
|
||||
|
|
|
@ -203,9 +203,11 @@ pub fn to_str(t: &Token) -> StrBuf {
|
|||
res.push_char('\'');
|
||||
res
|
||||
}
|
||||
LIT_INT(i, t) => ast_util::int_ty_to_str(t, Some(i)),
|
||||
LIT_UINT(u, t) => ast_util::uint_ty_to_str(t, Some(u)),
|
||||
LIT_INT_UNSUFFIXED(i) => { i.to_str().to_strbuf() }
|
||||
LIT_INT(i, t) => ast_util::int_ty_to_str(t, Some(i),
|
||||
ast_util::ForceSuffix),
|
||||
LIT_UINT(u, t) => ast_util::uint_ty_to_str(t, Some(u),
|
||||
ast_util::ForceSuffix),
|
||||
LIT_INT_UNSUFFIXED(i) => { (i as u64).to_str().to_strbuf() }
|
||||
LIT_FLOAT(s, t) => {
|
||||
let mut body = StrBuf::from_str(get_ident(s).get());
|
||||
if body.as_slice().ends_with(".") {
|
||||
|
|
|
@ -168,7 +168,7 @@ pub fn tt_to_str(tt: &ast::TokenTree) -> StrBuf {
|
|||
}
|
||||
|
||||
pub fn tts_to_str(tts: &[ast::TokenTree]) -> StrBuf {
|
||||
to_str(|s| s.print_tts(&tts))
|
||||
to_str(|s| s.print_tts(tts))
|
||||
}
|
||||
|
||||
pub fn stmt_to_str(stmt: &ast::Stmt) -> StrBuf {
|
||||
|
@ -247,6 +247,15 @@ pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> StrBuf {
|
|||
}
|
||||
}
|
||||
|
||||
fn needs_parentheses(expr: &ast::Expr) -> bool {
|
||||
match expr.node {
|
||||
ast::ExprAssign(..) | ast::ExprBinary(..) |
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) |
|
||||
ast::ExprAssignOp(..) | ast::ExprCast(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> State<'a> {
|
||||
pub fn ibox(&mut self, u: uint) -> IoResult<()> {
|
||||
self.boxes.push(pp::Inconsistent);
|
||||
|
@ -714,7 +723,7 @@ impl<'a> State<'a> {
|
|||
try!(self.print_ident(item.ident));
|
||||
try!(self.cbox(indent_unit));
|
||||
try!(self.popen());
|
||||
try!(self.print_tts(&(tts.as_slice())));
|
||||
try!(self.print_tts(tts.as_slice()));
|
||||
try!(self.pclose());
|
||||
try!(self.end());
|
||||
}
|
||||
|
@ -830,9 +839,15 @@ impl<'a> State<'a> {
|
|||
/// expression arguments as expressions). It can be done! I think.
|
||||
pub fn print_tt(&mut self, tt: &ast::TokenTree) -> IoResult<()> {
|
||||
match *tt {
|
||||
ast::TTDelim(ref tts) => self.print_tts(&(tts.as_slice())),
|
||||
ast::TTDelim(ref tts) => self.print_tts(tts.as_slice()),
|
||||
ast::TTTok(_, ref tk) => {
|
||||
word(&mut self.s, parse::token::to_str(tk).as_slice())
|
||||
try!(word(&mut self.s, parse::token::to_str(tk).as_slice()));
|
||||
match *tk {
|
||||
parse::token::DOC_COMMENT(..) => {
|
||||
hardbreak(&mut self.s)
|
||||
}
|
||||
_ => Ok(())
|
||||
}
|
||||
}
|
||||
ast::TTSeq(_, ref tts, ref sep, zerok) => {
|
||||
try!(word(&mut self.s, "$("));
|
||||
|
@ -856,7 +871,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn print_tts(&mut self, tts: & &[ast::TokenTree]) -> IoResult<()> {
|
||||
pub fn print_tts(&mut self, tts: &[ast::TokenTree]) -> IoResult<()> {
|
||||
try!(self.ibox(0));
|
||||
for (i, tt) in tts.iter().enumerate() {
|
||||
if i != 0 {
|
||||
|
@ -1113,7 +1128,7 @@ impl<'a> State<'a> {
|
|||
try!(self.print_path(pth, false));
|
||||
try!(word(&mut self.s, "!"));
|
||||
try!(self.popen());
|
||||
try!(self.print_tts(&tts.as_slice()));
|
||||
try!(self.print_tts(tts.as_slice()));
|
||||
self.pclose()
|
||||
}
|
||||
}
|
||||
|
@ -1136,6 +1151,18 @@ impl<'a> State<'a> {
|
|||
self.pclose()
|
||||
}
|
||||
|
||||
pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> IoResult<()> {
|
||||
let needs_par = needs_parentheses(expr);
|
||||
if needs_par {
|
||||
try!(self.popen());
|
||||
}
|
||||
try!(self.print_expr(expr));
|
||||
if needs_par {
|
||||
try!(self.pclose());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> {
|
||||
try!(self.maybe_print_comment(expr.span.lo));
|
||||
try!(self.ibox(indent_unit));
|
||||
|
@ -1209,7 +1236,7 @@ impl<'a> State<'a> {
|
|||
try!(self.pclose());
|
||||
}
|
||||
ast::ExprCall(func, ref args) => {
|
||||
try!(self.print_expr(func));
|
||||
try!(self.print_expr_maybe_paren(func));
|
||||
try!(self.print_call_post(args.as_slice()));
|
||||
}
|
||||
ast::ExprMethodCall(ident, ref tys, ref args) => {
|
||||
|
@ -1233,17 +1260,12 @@ impl<'a> State<'a> {
|
|||
}
|
||||
ast::ExprUnary(op, expr) => {
|
||||
try!(word(&mut self.s, ast_util::unop_to_str(op)));
|
||||
try!(self.print_expr(expr));
|
||||
try!(self.print_expr_maybe_paren(expr));
|
||||
}
|
||||
ast::ExprAddrOf(m, expr) => {
|
||||
try!(word(&mut self.s, "&"));
|
||||
try!(self.print_mutability(m));
|
||||
// Avoid `& &e` => `&&e`.
|
||||
match (m, &expr.node) {
|
||||
(ast::MutImmutable, &ast::ExprAddrOf(..)) => try!(space(&mut self.s)),
|
||||
_ => { }
|
||||
}
|
||||
try!(self.print_expr(expr));
|
||||
try!(self.print_expr_maybe_paren(expr));
|
||||
}
|
||||
ast::ExprLit(lit) => try!(self.print_literal(lit)),
|
||||
ast::ExprCast(expr, ty) => {
|
||||
|
@ -1474,22 +1496,27 @@ impl<'a> State<'a> {
|
|||
try!(self.popen());
|
||||
try!(self.print_string(a.asm.get(), a.asm_str_style));
|
||||
try!(self.word_space(":"));
|
||||
for &(ref co, o) in a.outputs.iter() {
|
||||
try!(self.print_string(co.get(), ast::CookedStr));
|
||||
try!(self.popen());
|
||||
try!(self.print_expr(o));
|
||||
try!(self.pclose());
|
||||
try!(self.word_space(","));
|
||||
}
|
||||
|
||||
try!(self.commasep(Inconsistent, a.outputs.as_slice(), |s, &(ref co, o)| {
|
||||
try!(s.print_string(co.get(), ast::CookedStr));
|
||||
try!(s.popen());
|
||||
try!(s.print_expr(o));
|
||||
try!(s.pclose());
|
||||
Ok(())
|
||||
}));
|
||||
try!(space(&mut self.s));
|
||||
try!(self.word_space(":"));
|
||||
for &(ref co, o) in a.inputs.iter() {
|
||||
try!(self.print_string(co.get(), ast::CookedStr));
|
||||
try!(self.popen());
|
||||
try!(self.print_expr(o));
|
||||
try!(self.pclose());
|
||||
try!(self.word_space(","));
|
||||
}
|
||||
|
||||
try!(self.commasep(Inconsistent, a.inputs.as_slice(), |s, &(ref co, o)| {
|
||||
try!(s.print_string(co.get(), ast::CookedStr));
|
||||
try!(s.popen());
|
||||
try!(s.print_expr(o));
|
||||
try!(s.pclose());
|
||||
Ok(())
|
||||
}));
|
||||
try!(space(&mut self.s));
|
||||
try!(self.word_space(":"));
|
||||
|
||||
try!(self.print_string(a.clobbers.get(), ast::CookedStr));
|
||||
try!(self.pclose());
|
||||
}
|
||||
|
@ -2211,11 +2238,13 @@ impl<'a> State<'a> {
|
|||
}
|
||||
ast::LitInt(i, t) => {
|
||||
word(&mut self.s,
|
||||
ast_util::int_ty_to_str(t, Some(i)).as_slice())
|
||||
ast_util::int_ty_to_str(t, Some(i),
|
||||
ast_util::AutoSuffix).as_slice())
|
||||
}
|
||||
ast::LitUint(u, t) => {
|
||||
word(&mut self.s,
|
||||
ast_util::uint_ty_to_str(t, Some(u)).as_slice())
|
||||
ast_util::uint_ty_to_str(t, Some(u),
|
||||
ast_util::ForceSuffix).as_slice())
|
||||
}
|
||||
ast::LitIntUnsuffixed(i) => {
|
||||
word(&mut self.s, format!("{}", i))
|
||||
|
|
|
@ -754,3 +754,9 @@ LLVMRustGetSectionName(LLVMSectionIteratorRef SI, const char **ptr) {
|
|||
*ptr = ret.data();
|
||||
return ret.size();
|
||||
}
|
||||
|
||||
// LLVMArrayType function does not support 64-bit ElementCount
|
||||
extern "C" LLVMTypeRef
|
||||
LLVMRustArrayType(LLVMTypeRef ElementType, uint64_t ElementCount) {
|
||||
return wrap(ArrayType::get(unwrap(ElementType), ElementCount));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// 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 static BLOCK_FN_DEF: fn(uint) -> uint = {
|
||||
fn foo(a: uint) -> uint {
|
||||
a + 10
|
||||
}
|
||||
foo
|
||||
};
|
|
@ -1,5 +1,3 @@
|
|||
// ignore-pretty
|
||||
|
||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
@ -10,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty very bad with line comments
|
||||
|
||||
extern crate collections;
|
||||
extern crate rand;
|
||||
extern crate time;
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
// except according to those terms.
|
||||
|
||||
// ignore-android: FIXME(#10393)
|
||||
// ignore-pretty very bad with line comments
|
||||
|
||||
// ignore-pretty the `let to_child` line gets an extra newline
|
||||
// multi tasking k-nucleotide
|
||||
|
||||
extern crate collections;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
// except according to those terms.
|
||||
|
||||
// ignore-android see #10393 #13206
|
||||
// ignore-pretty
|
||||
|
||||
extern crate sync;
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty very bad with line comments
|
||||
|
||||
extern crate sync;
|
||||
|
||||
use std::io;
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty very bad with line comments
|
||||
// ignore-android doesn't terminate?
|
||||
// ignore-pretty
|
||||
|
||||
use std::iter::range_step;
|
||||
use std::io::{stdin, stdout, File};
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// ignore-pretty
|
||||
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
@ -10,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty very bad with line comments
|
||||
|
||||
#![feature(managed_boxes)]
|
||||
|
||||
use std::io;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// ignore-pretty
|
||||
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
@ -17,6 +15,8 @@
|
|||
//
|
||||
// The filename is a song reference; google it in quotes.
|
||||
|
||||
// ignore-pretty very bad with line comments
|
||||
|
||||
use std::comm;
|
||||
use std::os;
|
||||
use std::task;
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty -- comments are unfaithfully preserved
|
||||
|
||||
#![allow(unused_variable)]
|
||||
#![allow(dead_assignment)]
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty -- comments are unfaithfully preserved
|
||||
|
||||
fn main() {
|
||||
let mut x: Option<int> = None;
|
||||
match x {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// ignore-pretty
|
||||
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// ignore-pretty
|
||||
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// ignore-pretty
|
||||
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// ignore-pretty
|
||||
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// 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.
|
||||
|
||||
#![feature(macro_rules)]
|
||||
|
||||
static A: uint = { 1; 2 };
|
||||
//~^ ERROR: blocks in constants are limited to items and tail expressions
|
||||
|
||||
static B: uint = { { } 2 };
|
||||
//~^ ERROR: blocks in constants are limited to items and tail expressions
|
||||
|
||||
macro_rules! foo {
|
||||
() => (()) //~ ERROR: blocks in constants are limited to items and tail expressions
|
||||
}
|
||||
static C: uint = { foo!() 2 };
|
||||
|
||||
static D: uint = { let x = 4; 2 };
|
||||
//~^ ERROR: blocks in constants are limited to items and tail expressions
|
||||
|
||||
pub fn main() {
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
// error-pattern:runned an unexported test
|
||||
// compile-flags:--test
|
||||
// check-stdout
|
||||
// ignore-pretty: does not work well with `--test`
|
||||
|
||||
mod m {
|
||||
pub fn exported() { }
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
// check-stdout
|
||||
// error-pattern:task 'test_foo' failed at
|
||||
// compile-flags: --test
|
||||
// ignore-pretty: does not work well with `--test`
|
||||
|
||||
#[test]
|
||||
fn test_foo() {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
// error-pattern:should be a positive integer
|
||||
// compile-flags: --test
|
||||
// exec-env:RUST_TEST_TASKS=foo
|
||||
// ignore-pretty: does not work well with `--test`
|
||||
|
||||
#[test]
|
||||
fn do_nothing() {}
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// except according to those terms.
|
||||
|
||||
// ignore-android
|
||||
// ignore-pretty: does not work well with `--test`
|
||||
|
||||
#![feature(quote)]
|
||||
#![deny(unused_variable)]
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty
|
||||
// aux-build:anon-extern-mod-cross-crate-1.rs
|
||||
extern crate anonexternmod;
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(managed_boxes)]
|
||||
|
||||
#[deriving(Eq, Show)]
|
||||
struct Point { x : int }
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ fn runtest(me: &str) {
|
|||
env: Some(env.as_slice()),
|
||||
.. ProcessConfig::new()
|
||||
}).unwrap();
|
||||
let out = p.wait_with_output();
|
||||
let out = p.wait_with_output().unwrap();
|
||||
assert!(!out.status.success());
|
||||
let s = str::from_utf8(out.error.as_slice()).unwrap();
|
||||
assert!(s.contains("stack backtrace") && s.contains("foo::h"),
|
||||
|
@ -62,7 +62,7 @@ fn runtest(me: &str) {
|
|||
args: ["fail".to_owned()],
|
||||
.. ProcessConfig::new()
|
||||
}).unwrap();
|
||||
let out = p.wait_with_output();
|
||||
let out = p.wait_with_output().unwrap();
|
||||
assert!(!out.status.success());
|
||||
let s = str::from_utf8(out.error.as_slice()).unwrap();
|
||||
assert!(!s.contains("stack backtrace") && !s.contains("foo::h"),
|
||||
|
@ -74,7 +74,7 @@ fn runtest(me: &str) {
|
|||
args: ["double-fail".to_owned()],
|
||||
.. ProcessConfig::new()
|
||||
}).unwrap();
|
||||
let out = p.wait_with_output();
|
||||
let out = p.wait_with_output().unwrap();
|
||||
assert!(!out.status.success());
|
||||
let s = str::from_utf8(out.error.as_slice()).unwrap();
|
||||
assert!(s.contains("stack backtrace") && s.contains("double::h"),
|
||||
|
@ -87,7 +87,7 @@ fn runtest(me: &str) {
|
|||
env: Some(env.as_slice()),
|
||||
.. ProcessConfig::new()
|
||||
}).unwrap();
|
||||
let out = p.wait_with_output();
|
||||
let out = p.wait_with_output().unwrap();
|
||||
assert!(!out.status.success());
|
||||
let s = str::from_utf8(out.error.as_slice()).unwrap();
|
||||
let mut i = 0;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// ignore-pretty
|
||||
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
@ -18,4 +16,5 @@ pub fn main() {
|
|||
|
||||
assert_eq!(-2147483648i32 - 1i32, 2147483647i32);
|
||||
assert_eq!(-9223372036854775808i64 - 1i64, 9223372036854775807i64);
|
||||
assert_eq!(-9223372036854775808 - 1, 9223372036854775807);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
// Binop corner cases
|
||||
|
||||
#![feature(managed_boxes)]
|
||||
|
||||
fn test_nil() {
|
||||
assert_eq!((), ());
|
||||
assert!((!(() != ())));
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// ignore-pretty
|
||||
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
@ -10,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty
|
||||
|
||||
fn match_ref(v: Option<int>) -> int {
|
||||
match v {
|
||||
Some(ref i) => {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
#![feature(managed_boxes)]
|
||||
|
||||
pub fn main() {
|
||||
assert!((@1 < @3));
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty #13324
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn foo<T>() {}
|
||||
|
@ -45,6 +43,12 @@ fn g<'a>(a: &'a int, f: proc<'b>(&'b int) -> &'b int) -> &'a int {
|
|||
f(a)
|
||||
}
|
||||
|
||||
struct A;
|
||||
|
||||
impl A {
|
||||
fn foo<T>(&self) {}
|
||||
}
|
||||
|
||||
fn bar<'b>() {
|
||||
foo::<||>();
|
||||
foo::<|| -> ()>();
|
||||
|
@ -60,17 +64,25 @@ fn bar<'b>() {
|
|||
foo::<proc():Share>();
|
||||
foo::<proc<'a>(int, f32, &'a int):'static + Share -> &'a int>();
|
||||
|
||||
foo::<<'a>||>();
|
||||
|
||||
// issue #11209
|
||||
let _: ||: 'b; // for comparison
|
||||
let _: <'a> ||;
|
||||
|
||||
let _: Option<||:'b>;
|
||||
// let _: Option<<'a>||>;
|
||||
let _: Option<<'a>||>;
|
||||
let _: Option< <'a>||>;
|
||||
|
||||
// issue #11210
|
||||
let _: ||: 'static;
|
||||
|
||||
let a = A;
|
||||
a.foo::<<'a>||>();
|
||||
}
|
||||
|
||||
struct B<T>;
|
||||
impl<'b> B<<'a>||: 'b> {}
|
||||
|
||||
pub fn main() {
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <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.
|
||||
|
||||
// aux-build:cci_const_block.rs
|
||||
|
||||
extern crate cci_const_block;
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(cci_const_block::BLOCK_FN_DEF(390), 400);
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// 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.
|
||||
|
||||
// General test that function items in static blocks
|
||||
// can be generated with a macro.
|
||||
|
||||
#![feature(macro_rules)]
|
||||
|
||||
struct MyType {
|
||||
desc: &'static str,
|
||||
data: uint,
|
||||
code: fn(uint, uint) -> uint
|
||||
}
|
||||
|
||||
impl MyType {
|
||||
fn eval(&self, a: uint) -> uint {
|
||||
(self.code)(self.data, a)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! codegen {
|
||||
($e:expr, $v:expr) => {
|
||||
{
|
||||
fn generated(a: uint, b: uint) -> uint {
|
||||
a - ($e * b)
|
||||
}
|
||||
MyType {
|
||||
desc: "test",
|
||||
data: $v,
|
||||
code: generated
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GENERATED_CODE_1: MyType = codegen!(2, 100);
|
||||
static GENERATED_CODE_2: MyType = codegen!(5, 1000);
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(GENERATED_CODE_1.eval(10), 80);
|
||||
assert_eq!(GENERATED_CODE_2.eval(100), 500);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// 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.
|
||||
|
||||
#![feature(macro_rules)]
|
||||
|
||||
mod foo {
|
||||
pub trait Value {
|
||||
fn value(&self) -> uint;
|
||||
}
|
||||
}
|
||||
|
||||
static BLOCK_USE: uint = {
|
||||
use foo::Value;
|
||||
100
|
||||
};
|
||||
|
||||
static BLOCK_PUB_USE: uint = {
|
||||
pub use foo::Value;
|
||||
200
|
||||
};
|
||||
|
||||
static BLOCK_STRUCT_DEF: uint = {
|
||||
struct Foo {
|
||||
a: uint
|
||||
}
|
||||
Foo{ a: 300 }.a
|
||||
};
|
||||
|
||||
static BLOCK_FN_DEF: fn(uint) -> uint = {
|
||||
fn foo(a: uint) -> uint {
|
||||
a + 10
|
||||
}
|
||||
foo
|
||||
};
|
||||
|
||||
static BLOCK_MACRO_RULES: uint = {
|
||||
macro_rules! baz {
|
||||
() => (412)
|
||||
}
|
||||
baz!()
|
||||
};
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(BLOCK_USE, 100);
|
||||
assert_eq!(BLOCK_PUB_USE, 200);
|
||||
assert_eq!(BLOCK_STRUCT_DEF, 300);
|
||||
assert_eq!(BLOCK_FN_DEF(390), 400);
|
||||
assert_eq!(BLOCK_MACRO_RULES, 412);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <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(dead_code)]
|
||||
#![allow(unused_unsafe)]
|
||||
|
||||
struct Foo {
|
||||
a: uint,
|
||||
b: *()
|
||||
}
|
||||
|
||||
fn foo<T>(a: T) -> T {
|
||||
a
|
||||
}
|
||||
|
||||
static BLOCK_INTEGRAL: uint = { 1 };
|
||||
static BLOCK_EXPLICIT_UNIT: () = { () };
|
||||
static BLOCK_IMPLICIT_UNIT: () = { };
|
||||
static BLOCK_FLOAT: f64 = { 1.0 };
|
||||
static BLOCK_ENUM: Option<uint> = { Some(100) };
|
||||
static BLOCK_STRUCT: Foo = { Foo { a: 12, b: 0 as *() } };
|
||||
static BLOCK_UNSAFE: uint = unsafe { 1000 };
|
||||
|
||||
// FIXME: #13970
|
||||
// static BLOCK_FN_INFERRED: fn(uint) -> uint = { foo };
|
||||
|
||||
// FIXME: #13971
|
||||
// static BLOCK_FN: fn(uint) -> uint = { foo::<uint> };
|
||||
|
||||
// FIXME: #13972
|
||||
// static BLOCK_ENUM_CONSTRUCTOR: fn(uint) -> Option<uint> = { Some };
|
||||
|
||||
// FIXME: #13973
|
||||
// static BLOCK_UNSAFE_SAFE_PTR: &'static int = unsafe { &*(0xdeadbeef as *int) };
|
||||
// static BLOCK_UNSAFE_SAFE_PTR_2: &'static int = unsafe {
|
||||
// static X: *int = 0xdeadbeef as *int;
|
||||
// &*X
|
||||
// };
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(BLOCK_INTEGRAL, 1);
|
||||
assert_eq!(BLOCK_EXPLICIT_UNIT, ());
|
||||
assert_eq!(BLOCK_IMPLICIT_UNIT, ());
|
||||
assert_eq!(BLOCK_FLOAT, 1.0_f64);
|
||||
assert_eq!(BLOCK_STRUCT.a, 12);
|
||||
assert_eq!(BLOCK_STRUCT.b, 0 as *());
|
||||
assert_eq!(BLOCK_ENUM, Some(100));
|
||||
assert_eq!(BLOCK_UNSAFE, 1000);
|
||||
|
||||
// FIXME: #13970
|
||||
// assert_eq!(BLOCK_FN_INFERRED(300), 300);
|
||||
|
||||
// FIXME: #13971
|
||||
// assert_eq!(BLOCK_FN(300), 300);
|
||||
|
||||
// FIXME: #13972
|
||||
// assert_eq!(BLOCK_ENUM_CONSTRUCTOR(200), Some(200));
|
||||
|
||||
// FIXME: #13973
|
||||
// assert_eq!(BLOCK_UNSAFE_SAFE_PTR as *int as uint, 0xdeadbeef_u);
|
||||
// assert_eq!(BLOCK_UNSAFE_SAFE_PTR_2 as *int as uint, 0xdeadbeef_u);
|
||||
}
|
|
@ -120,7 +120,7 @@ pub fn test_destroy_actually_kills(force: bool) {
|
|||
() = rx1.recv() => {}
|
||||
}
|
||||
});
|
||||
match p.wait() {
|
||||
match p.wait().unwrap() {
|
||||
ExitStatus(..) => fail!("expected a signal"),
|
||||
ExitSignal(..) => tx.send(()),
|
||||
}
|
||||
|
|
|
@ -8,20 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty - does not converge
|
||||
|
||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <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.
|
||||
|
||||
extern crate serialize; // {En,De}codable
|
||||
extern crate rand; // Rand
|
||||
extern crate serialize;
|
||||
extern crate rand;
|
||||
|
||||
mod submod {
|
||||
// if any of these are implemented without global calls for any
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty: pprust doesn't print hygiene output
|
||||
|
||||
#![feature(macro_rules)]
|
||||
|
||||
macro_rules! loop_x {
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-pretty-expanded unnecessary unsafe block generated
|
||||
|
||||
#![feature(macro_rules)]
|
||||
#![feature(macro_rules, managed_boxes)]
|
||||
#![deny(warnings)]
|
||||
#![allow(unused_must_use)]
|
||||
#![allow(deprecated_owned_vector)]
|
||||
|
@ -76,6 +77,7 @@ pub fn main() {
|
|||
t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
|
||||
t!(format!("{} {0}", "a"), "a a");
|
||||
t!(format!("{foo_bar}", foo_bar=1), "1");
|
||||
t!(format!("{:d}", 5 + 5), "10");
|
||||
|
||||
// Methods should probably work
|
||||
t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue