mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 00:03:43 +00:00
Auto merge of #24177 - alexcrichton:rustdoc, r=aturon
This commit series starts out with more official test harness support for rustdoc tests, and then each commit afterwards adds a test (where appropriate). Each commit should also test and finish independently of all others (they're all pretty separable). I've uploaded a [copy of the documentation](http://people.mozilla.org/~acrichton/doc/std/) generated after all these commits were applied, and a double check on issues being closed would be greatly appreciated! I'll also browse the docs a bit and make sure nothing regressed too horribly.
This commit is contained in:
commit
c897ac04e2
1
configure
vendored
1
configure
vendored
@ -1128,6 +1128,7 @@ do
|
||||
make_dir $h/test/debuginfo-gdb
|
||||
make_dir $h/test/debuginfo-lldb
|
||||
make_dir $h/test/codegen
|
||||
make_dir $h/test/rustdoc
|
||||
done
|
||||
|
||||
# Configure submodules
|
||||
|
35
mk/crates.mk
35
mk/crates.mk
@ -118,42 +118,13 @@ ONLY_RLIB_collections := 1
|
||||
ONLY_RLIB_unicode := 1
|
||||
ONLY_RLIB_rustc_bitflags := 1
|
||||
|
||||
# Documented-by-default crates
|
||||
DOC_CRATES := std alloc collections core libc unicode
|
||||
|
||||
################################################################################
|
||||
# You should not need to edit below this line
|
||||
################################################################################
|
||||
|
||||
# On channels where the only usable crate is std, only build documentation for
|
||||
# std. This keeps distributions small and doesn't clutter up the API docs with
|
||||
# confusing internal details from the crates behind the facade.
|
||||
#
|
||||
# (Disabled while cmr figures out how to change rustdoc to make reexports work
|
||||
# slightly nicer. Otherwise, all cross-crate links to Vec will go to
|
||||
# libcollections, breaking them, and [src] links for anything reexported will
|
||||
# not work.)
|
||||
|
||||
#ifeq ($(CFG_RELEASE_CHANNEL),stable)
|
||||
#DOC_CRATES := std
|
||||
#else
|
||||
#ifeq ($(CFG_RELEASE_CHANNEL),beta)
|
||||
#DOC_CRATES := std
|
||||
#else
|
||||
DOC_CRATES := $(filter-out rustc, \
|
||||
$(filter-out rustc_trans, \
|
||||
$(filter-out rustc_typeck, \
|
||||
$(filter-out rustc_borrowck, \
|
||||
$(filter-out rustc_resolve, \
|
||||
$(filter-out rustc_driver, \
|
||||
$(filter-out rustc_privacy, \
|
||||
$(filter-out rustc_lint, \
|
||||
$(filter-out log, \
|
||||
$(filter-out getopts, \
|
||||
$(filter-out syntax, $(CRATES))))))))))))
|
||||
#endif
|
||||
#endif
|
||||
COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \
|
||||
rustc_typeck rustc_driver syntax rustc_privacy \
|
||||
rustc_lint
|
||||
|
||||
# This macro creates some simple definitions for each crate being built, just
|
||||
# some munging of all of the parameters above.
|
||||
#
|
||||
|
10
mk/docs.mk
10
mk/docs.mk
@ -250,18 +250,20 @@ endif
|
||||
doc/$(1)/:
|
||||
$$(Q)mkdir -p $$@
|
||||
|
||||
$(2) += doc/$(1)/index.html
|
||||
doc/$(1)/index.html: CFG_COMPILER_HOST_TRIPLE = $(CFG_TARGET)
|
||||
doc/$(1)/index.html: $$(LIB_DOC_DEP_$(1)) doc/$(1)/
|
||||
@$$(call E, rustdoc: $$@)
|
||||
$$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(CFG_BUILD)) \
|
||||
$$(RUSTDOC) --cfg dox --cfg stage2 $$<
|
||||
$$(RUSTDOC) --cfg dox --cfg stage2 $$(RUSTFLAGS_$(1)) $$<
|
||||
endef
|
||||
|
||||
$(foreach crate,$(DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),DOC_TARGETS)))
|
||||
$(foreach crate,$(CRATES),$(eval $(call DEF_LIB_DOC,$(crate))))
|
||||
|
||||
COMPILER_DOC_TARGETS := $(CRATES:%=doc/%/index.html)
|
||||
ifdef CFG_COMPILER_DOCS
|
||||
$(foreach crate,$(COMPILER_DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),COMPILER_DOC_TARGETS)))
|
||||
DOC_TARGETS += $(COMPILER_DOC_TARGETS)
|
||||
else
|
||||
DOC_TARGETS += $(DOC_CRATES:%=doc/%/index.html)
|
||||
endif
|
||||
|
||||
ifdef CFG_DISABLE_DOCS
|
||||
|
23
mk/tests.mk
23
mk/tests.mk
@ -22,9 +22,11 @@ $(eval $(call RUST_CRATE,coretest))
|
||||
DEPS_collectionstest :=
|
||||
$(eval $(call RUST_CRATE,collectionstest))
|
||||
|
||||
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) collectionstest coretest
|
||||
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) \
|
||||
collectionstest coretest
|
||||
TEST_DOC_CRATES = $(DOC_CRATES)
|
||||
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve rustc_trans rustc_lint,\
|
||||
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve \
|
||||
rustc_trans rustc_lint,\
|
||||
$(HOST_CRATES))
|
||||
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
|
||||
|
||||
@ -304,6 +306,7 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rmake-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rustdocck-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-crates-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-crates-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-bench-exec \
|
||||
@ -471,6 +474,7 @@ DEBUGINFO_GDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
|
||||
DEBUGINFO_LLDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
|
||||
CODEGEN_RS := $(wildcard $(S)src/test/codegen/*.rs)
|
||||
CODEGEN_CC := $(wildcard $(S)src/test/codegen/*.cc)
|
||||
RUSTDOCCK_RS := $(wildcard $(S)src/test/rustdoc/*.rs)
|
||||
|
||||
# perf tests are the same as bench tests only they run under
|
||||
# a performance monitor.
|
||||
@ -489,6 +493,7 @@ PRETTY_TESTS := $(PRETTY_RS)
|
||||
DEBUGINFO_GDB_TESTS := $(DEBUGINFO_GDB_RS)
|
||||
DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS)
|
||||
CODEGEN_TESTS := $(CODEGEN_RS) $(CODEGEN_CC)
|
||||
RUSTDOCCK_TESTS := $(RUSTDOCCK_RS)
|
||||
|
||||
CTEST_SRC_BASE_rpass = run-pass
|
||||
CTEST_BUILD_BASE_rpass = run-pass
|
||||
@ -550,6 +555,11 @@ CTEST_BUILD_BASE_codegen = codegen
|
||||
CTEST_MODE_codegen = codegen
|
||||
CTEST_RUNTOOL_codegen = $(CTEST_RUNTOOL)
|
||||
|
||||
CTEST_SRC_BASE_rustdocck = rustdoc
|
||||
CTEST_BUILD_BASE_rustdocck = rustdoc
|
||||
CTEST_MODE_rustdocck = rustdoc
|
||||
CTEST_RUNTOOL_rustdocck = $(CTEST_RUNTOOL)
|
||||
|
||||
# CTEST_DISABLE_$(TEST_GROUP), if set, will cause the test group to be
|
||||
# disabled and the associated message to be printed as a warning
|
||||
# during attempts to run those tests.
|
||||
@ -618,12 +628,14 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \
|
||||
--compile-lib-path $$(HLIB$(1)_H_$(3)) \
|
||||
--run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \
|
||||
--rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
|
||||
--rustdoc-path $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
|
||||
--clang-path $(if $(CFG_CLANG),$(CFG_CLANG),clang) \
|
||||
--llvm-bin-path $(CFG_LLVM_INST_DIR_$(CFG_BUILD))/bin \
|
||||
--aux-base $$(S)src/test/auxiliary/ \
|
||||
--stage-id stage$(1)-$(2) \
|
||||
--target $(2) \
|
||||
--host $(3) \
|
||||
--python $$(CFG_PYTHON) \
|
||||
--gdb-version="$(CFG_GDB_VERSION)" \
|
||||
--lldb-version="$(CFG_LLDB_VERSION)" \
|
||||
--android-cross-path=$(CFG_ANDROID_CROSS_PATH) \
|
||||
@ -660,6 +672,9 @@ CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \
|
||||
$(S)src/etc/lldb_batchmode.py \
|
||||
$(S)src/etc/lldb_rust_formatters.py
|
||||
CTEST_DEPS_codegen_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_TESTS)
|
||||
CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \
|
||||
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
|
||||
$(S)src/etc/htmldocck.py
|
||||
|
||||
endef
|
||||
|
||||
@ -722,7 +737,8 @@ endif
|
||||
|
||||
endef
|
||||
|
||||
CTEST_NAMES = rpass rpass-valgrind rpass-full cfail-full rfail cfail pfail bench perf debuginfo-gdb debuginfo-lldb codegen
|
||||
CTEST_NAMES = rpass rpass-valgrind rpass-full cfail-full rfail cfail pfail \
|
||||
bench perf debuginfo-gdb debuginfo-lldb codegen rustdocck
|
||||
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(eval $(foreach target,$(CFG_TARGET), \
|
||||
@ -890,6 +906,7 @@ TEST_GROUPS = \
|
||||
bench \
|
||||
perf \
|
||||
rmake \
|
||||
rustdocck \
|
||||
debuginfo-gdb \
|
||||
debuginfo-lldb \
|
||||
codegen \
|
||||
|
@ -23,7 +23,8 @@ pub enum Mode {
|
||||
Pretty,
|
||||
DebugInfoGdb,
|
||||
DebugInfoLldb,
|
||||
Codegen
|
||||
Codegen,
|
||||
Rustdoc,
|
||||
}
|
||||
|
||||
impl FromStr for Mode {
|
||||
@ -39,6 +40,7 @@ impl FromStr for Mode {
|
||||
"debuginfo-lldb" => Ok(DebugInfoLldb),
|
||||
"debuginfo-gdb" => Ok(DebugInfoGdb),
|
||||
"codegen" => Ok(Codegen),
|
||||
"rustdoc" => Ok(Rustdoc),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
@ -56,6 +58,7 @@ impl fmt::Display for Mode {
|
||||
DebugInfoGdb => "debuginfo-gdb",
|
||||
DebugInfoLldb => "debuginfo-lldb",
|
||||
Codegen => "codegen",
|
||||
Rustdoc => "rustdoc",
|
||||
}, f)
|
||||
}
|
||||
}
|
||||
@ -71,6 +74,12 @@ pub struct Config {
|
||||
// The rustc executable
|
||||
pub rustc_path: PathBuf,
|
||||
|
||||
// The rustdoc executable
|
||||
pub rustdoc_path: PathBuf,
|
||||
|
||||
// The python executable
|
||||
pub python: String,
|
||||
|
||||
// The clang executable
|
||||
pub clang_path: Option<PathBuf>,
|
||||
|
||||
|
@ -60,6 +60,8 @@ pub fn parse_config(args: Vec<String> ) -> Config {
|
||||
vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
|
||||
reqopt("", "run-lib-path", "path to target shared libraries", "PATH"),
|
||||
reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"),
|
||||
reqopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH"),
|
||||
reqopt("", "python", "path to python to use for doc tests", "PATH"),
|
||||
optopt("", "clang-path", "path to executable for codegen tests", "PATH"),
|
||||
optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM"),
|
||||
optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind"),
|
||||
@ -128,6 +130,8 @@ pub fn parse_config(args: Vec<String> ) -> 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"),
|
||||
rustdoc_path: opt_path(matches, "rustdoc-path"),
|
||||
python: matches.opt_str("python").unwrap(),
|
||||
clang_path: matches.opt_str("clang-path").map(|s| PathBuf::from(&s)),
|
||||
valgrind_path: matches.opt_str("valgrind-path"),
|
||||
force_valgrind: matches.opt_present("force-valgrind"),
|
||||
@ -168,6 +172,7 @@ pub fn log_config(config: &Config) {
|
||||
logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path));
|
||||
logv(c, format!("run_lib_path: {:?}", config.run_lib_path));
|
||||
logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
|
||||
logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path.display()));
|
||||
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));
|
||||
|
@ -12,7 +12,7 @@ use self::TargetLocation::*;
|
||||
|
||||
use common::Config;
|
||||
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
|
||||
use common::{Codegen, DebugInfoLldb, DebugInfoGdb};
|
||||
use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc};
|
||||
use errors;
|
||||
use header::TestProps;
|
||||
use header;
|
||||
@ -57,15 +57,16 @@ pub fn run_metrics(config: Config, testfile: &Path, mm: &mut MetricMap) {
|
||||
let props = header::load_props(&testfile);
|
||||
debug!("loaded props");
|
||||
match config.mode {
|
||||
CompileFail => run_cfail_test(&config, &props, &testfile),
|
||||
ParseFail => run_cfail_test(&config, &props, &testfile),
|
||||
RunFail => run_rfail_test(&config, &props, &testfile),
|
||||
RunPass => run_rpass_test(&config, &props, &testfile),
|
||||
RunPassValgrind => run_valgrind_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),
|
||||
CompileFail => run_cfail_test(&config, &props, &testfile),
|
||||
ParseFail => run_cfail_test(&config, &props, &testfile),
|
||||
RunFail => run_rfail_test(&config, &props, &testfile),
|
||||
RunPass => run_rpass_test(&config, &props, &testfile),
|
||||
RunPassValgrind => run_valgrind_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),
|
||||
Rustdoc => run_rustdoc_test(&config, &props, &testfile),
|
||||
}
|
||||
}
|
||||
|
||||
@ -725,32 +726,37 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
|
||||
-> ProcRes {
|
||||
// Prepare the lldb_batchmode which executes the debugger script
|
||||
let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
|
||||
cmd2procres(config,
|
||||
test_executable,
|
||||
Command::new(&config.python)
|
||||
.arg(&lldb_script_path)
|
||||
.arg(test_executable)
|
||||
.arg(debugger_script)
|
||||
.env("PYTHONPATH",
|
||||
config.lldb_python_dir.as_ref().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
let mut cmd = Command::new("python");
|
||||
cmd.arg(&lldb_script_path)
|
||||
.arg(test_executable)
|
||||
.arg(debugger_script)
|
||||
.env("PYTHONPATH", config.lldb_python_dir.as_ref().unwrap());
|
||||
fn cmd2procres(config: &Config, test_executable: &Path, cmd: &mut Command)
|
||||
-> ProcRes {
|
||||
let (status, out, err) = match cmd.output() {
|
||||
Ok(Output { status, stdout, stderr }) => {
|
||||
(status,
|
||||
String::from_utf8(stdout).unwrap(),
|
||||
String::from_utf8(stderr).unwrap())
|
||||
},
|
||||
Err(e) => {
|
||||
fatal(&format!("Failed to setup Python process for \
|
||||
LLDB script: {}", e))
|
||||
}
|
||||
};
|
||||
|
||||
let (status, out, err) = match cmd.output() {
|
||||
Ok(Output { status, stdout, stderr }) => {
|
||||
(status,
|
||||
String::from_utf8(stdout).unwrap(),
|
||||
String::from_utf8(stderr).unwrap())
|
||||
},
|
||||
Err(e) => {
|
||||
fatal(&format!("Failed to setup Python process for \
|
||||
LLDB script: {}", e))
|
||||
}
|
||||
};
|
||||
|
||||
dump_output(config, test_executable, &out, &err);
|
||||
return ProcRes {
|
||||
status: Status::Normal(status),
|
||||
stdout: out,
|
||||
stderr: err,
|
||||
cmdline: format!("{:?}", cmd)
|
||||
};
|
||||
dump_output(config, test_executable, &out, &err);
|
||||
ProcRes {
|
||||
status: Status::Normal(status),
|
||||
stdout: out,
|
||||
stderr: err,
|
||||
cmdline: format!("{:?}", cmd)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1157,6 +1163,26 @@ fn compile_test_(config: &Config, props: &TestProps,
|
||||
compose_and_run_compiler(config, props, testfile, args, None)
|
||||
}
|
||||
|
||||
fn document(config: &Config, props: &TestProps,
|
||||
testfile: &Path, extra_args: &[String]) -> (ProcRes, PathBuf) {
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
let out_dir = output_base_name(config, testfile);
|
||||
let _ = fs::remove_dir_all(&out_dir);
|
||||
ensure_dir(&out_dir);
|
||||
let mut args = vec!["-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string(),
|
||||
"-o".to_string(),
|
||||
out_dir.to_str().unwrap().to_string(),
|
||||
testfile.to_str().unwrap().to_string()];
|
||||
args.extend(extra_args.iter().cloned());
|
||||
args.extend(split_maybe_args(&props.compile_flags).into_iter());
|
||||
let args = ProcArgs {
|
||||
prog: config.rustdoc_path.to_str().unwrap().to_string(),
|
||||
args: args,
|
||||
};
|
||||
(compose_and_run_compiler(config, props, testfile, args, None), out_dir)
|
||||
}
|
||||
|
||||
fn exec_compiled_test(config: &Config, props: &TestProps,
|
||||
testfile: &Path) -> ProcRes {
|
||||
|
||||
@ -1181,20 +1207,17 @@ fn exec_compiled_test(config: &Config, props: &TestProps,
|
||||
}
|
||||
}
|
||||
|
||||
fn compose_and_run_compiler(
|
||||
config: &Config,
|
||||
props: &TestProps,
|
||||
testfile: &Path,
|
||||
args: ProcArgs,
|
||||
input: Option<String>) -> ProcRes {
|
||||
|
||||
fn compose_and_run_compiler(config: &Config, props: &TestProps,
|
||||
testfile: &Path, args: ProcArgs,
|
||||
input: Option<String>) -> ProcRes {
|
||||
if !props.aux_builds.is_empty() {
|
||||
ensure_dir(&aux_output_dir_name(config, testfile));
|
||||
}
|
||||
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let extra_link_args = vec!("-L".to_string(), aux_dir.to_str().unwrap().to_string());
|
||||
let extra_link_args = vec!["-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string()];
|
||||
|
||||
for rel_ab in &props.aux_builds {
|
||||
let abs_ab = config.aux_base.join(rel_ab);
|
||||
@ -1330,8 +1353,8 @@ fn make_exe_name(config: &Config, testfile: &Path) -> PathBuf {
|
||||
f
|
||||
}
|
||||
|
||||
fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) ->
|
||||
ProcArgs {
|
||||
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
|
||||
let mut args = split_maybe_args(&config.runtool);
|
||||
@ -1797,3 +1820,21 @@ fn charset() -> &'static str {
|
||||
"UTF-8"
|
||||
}
|
||||
}
|
||||
|
||||
fn run_rustdoc_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
let (proc_res, out_dir) = document(config, props, testfile, &[]);
|
||||
if !proc_res.status.success() {
|
||||
fatal_proc_rec("rustdoc failed!", &proc_res);
|
||||
}
|
||||
let root = find_rust_src_root(config).unwrap();
|
||||
|
||||
let res = cmd2procres(config,
|
||||
testfile,
|
||||
Command::new(&config.python)
|
||||
.arg(root.join("src/etc/htmldocck.py"))
|
||||
.arg(out_dir)
|
||||
.arg(testfile));
|
||||
if !res.status.success() {
|
||||
fatal_proc_rec("htmldocck failed!", &res);
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,9 @@ This line does all of the work in our little program. There are a number of
|
||||
details that are important here. The first is that it's indented with four
|
||||
spaces, not tabs. Please configure your editor of choice to insert four spaces
|
||||
with the tab key. We provide some [sample configurations for various
|
||||
editors](https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md).
|
||||
editors][configs].
|
||||
|
||||
[configs]: https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md
|
||||
|
||||
The second point is the `println!()` part. This is calling a Rust *macro*,
|
||||
which is how metaprogramming is done in Rust. If it were a function instead, it
|
||||
|
@ -186,7 +186,8 @@ def concat_multi_lines(f):
|
||||
|
||||
firstlineno = firstlineno or lineno
|
||||
if line.endswith('\\'):
|
||||
lastline = line[:-1]
|
||||
if lastline is None:
|
||||
lastline = line[:-1]
|
||||
catenated += line[:-1]
|
||||
else:
|
||||
yield firstlineno, catenated + line
|
||||
|
@ -139,6 +139,7 @@ pub fn from_digit(num: u32, radix: u32) -> Option<char> {
|
||||
// NB: the stabilization and documentation for this trait is in
|
||||
// unicode/char.rs, not here
|
||||
#[allow(missing_docs)] // docs in libunicode/u_char.rs
|
||||
#[doc(hidden)]
|
||||
pub trait CharExt {
|
||||
fn is_digit(self, radix: u32) -> bool;
|
||||
fn to_digit(self, radix: u32) -> Option<u32>;
|
||||
|
@ -229,7 +229,6 @@ macro_rules! writeln {
|
||||
/// Iterators:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// fn divide_by_three(x: u32) -> u32 { // one of the poorest implementations of x/3
|
||||
/// for i in 0.. {
|
||||
/// if 3*i < i { panic!("u32 overflow"); }
|
||||
|
@ -2490,6 +2490,7 @@ pub enum FpCategory {
|
||||
// `unused_self`. Removing it requires #8888 to be fixed.
|
||||
#[unstable(feature = "core",
|
||||
reason = "distribution of methods between core/std is unclear")]
|
||||
#[doc(hidden)]
|
||||
pub trait Float
|
||||
: Copy + Clone
|
||||
+ NumCast
|
||||
|
@ -89,6 +89,7 @@
|
||||
//! of unsafe pointers in Rust.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "pointer")]
|
||||
|
||||
use mem;
|
||||
use clone::Clone;
|
||||
|
@ -63,6 +63,7 @@ use raw::Slice as RawSlice;
|
||||
|
||||
/// Extension methods for slices.
|
||||
#[allow(missing_docs)] // docs in libcollections
|
||||
#[doc(hidden)]
|
||||
pub trait SliceExt {
|
||||
type Item;
|
||||
|
||||
|
@ -1496,6 +1496,7 @@ impl<'a, S: ?Sized> Str for &'a S where S: Str {
|
||||
|
||||
/// Methods for string slices
|
||||
#[allow(missing_docs)]
|
||||
#[doc(hidden)]
|
||||
pub trait StrExt {
|
||||
// NB there are no docs here are they're all located on the StrExt trait in
|
||||
// libcollections, not here.
|
||||
|
@ -1264,7 +1264,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
encode_paren_sugar(rbml_w, trait_def.paren_sugar);
|
||||
encode_defaulted(rbml_w, ty::trait_has_default_impl(tcx, def_id));
|
||||
encode_associated_type_names(rbml_w, &trait_def.associated_type_names);
|
||||
encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates, tag_item_generics);
|
||||
encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates,
|
||||
tag_item_generics);
|
||||
encode_predicates(rbml_w, ecx, &ty::lookup_super_predicates(tcx, def_id),
|
||||
tag_item_super_predicates);
|
||||
encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
//! Support for inlining external documentation into the current AST.
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
@ -150,18 +152,21 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt,
|
||||
let def = ty::lookup_trait_def(tcx, did);
|
||||
let trait_items = ty::trait_items(tcx, did).clean(cx);
|
||||
let predicates = ty::lookup_predicates(tcx, did);
|
||||
let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx);
|
||||
let generics = filter_non_trait_generics(did, generics);
|
||||
let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
|
||||
clean::Trait {
|
||||
unsafety: def.unsafety,
|
||||
generics: (&def.generics, &predicates, subst::TypeSpace).clean(cx),
|
||||
generics: generics,
|
||||
items: trait_items,
|
||||
bounds: vec![], // supertraits can be found in the list of predicates
|
||||
bounds: supertrait_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Function {
|
||||
let t = ty::lookup_item_type(tcx, did);
|
||||
let (decl, style) = match t.ty.sty {
|
||||
ty::ty_bare_fn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety),
|
||||
let (decl, style, abi) = match t.ty.sty {
|
||||
ty::ty_bare_fn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
|
||||
_ => panic!("bad function"),
|
||||
};
|
||||
let predicates = ty::lookup_predicates(tcx, did);
|
||||
@ -169,6 +174,7 @@ fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) ->
|
||||
decl: decl,
|
||||
generics: (&t.generics, &predicates, subst::FnSpace).clean(cx),
|
||||
unsafety: style,
|
||||
abi: abi,
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,9 +337,10 @@ fn build_impl(cx: &DocContext,
|
||||
let did = assoc_ty.def_id;
|
||||
let type_scheme = ty::lookup_item_type(tcx, did);
|
||||
let predicates = ty::lookup_predicates(tcx, did);
|
||||
// Not sure the choice of ParamSpace actually matters here, because an
|
||||
// associated type won't have generics on the LHS
|
||||
let typedef = (type_scheme, predicates, subst::ParamSpace::TypeSpace).clean(cx);
|
||||
// Not sure the choice of ParamSpace actually matters here,
|
||||
// because an associated type won't have generics on the LHS
|
||||
let typedef = (type_scheme, predicates,
|
||||
subst::ParamSpace::TypeSpace).clean(cx);
|
||||
Some(clean::Item {
|
||||
name: Some(assoc_ty.name.clean(cx)),
|
||||
inner: clean::TypedefItem(typedef),
|
||||
@ -395,16 +402,19 @@ fn build_module(cx: &DocContext, tcx: &ty::ctxt,
|
||||
is_crate: false,
|
||||
};
|
||||
|
||||
// FIXME: this doesn't handle reexports inside the module itself.
|
||||
// Should they be handled?
|
||||
fn fill_in(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId,
|
||||
items: &mut Vec<clean::Item>) {
|
||||
// If we're reexporting a reexport it may actually reexport something in
|
||||
// two namespaces, so the target may be listed twice. Make sure we only
|
||||
// visit each node at most once.
|
||||
let mut visited = HashSet::new();
|
||||
csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, vis| {
|
||||
match def {
|
||||
decoder::DlDef(def::DefForeignMod(did)) => {
|
||||
fill_in(cx, tcx, did, items);
|
||||
}
|
||||
decoder::DlDef(def) if vis == ast::Public => {
|
||||
if !visited.insert(def) { return }
|
||||
match try_inline_def(cx, tcx, def) {
|
||||
Some(i) => items.extend(i.into_iter()),
|
||||
None => {}
|
||||
@ -446,3 +456,48 @@ fn build_static(cx: &DocContext, tcx: &ty::ctxt,
|
||||
expr: "\n\n\n".to_string(), // trigger the "[definition]" links
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait's generics clause actually contains all of the predicates for all of
|
||||
/// its associated types as well. We specifically move these clauses to the
|
||||
/// associated types instead when displaying, so when we're genering the
|
||||
/// generics for the trait itself we need to be sure to remove them.
|
||||
///
|
||||
/// The inverse of this filtering logic can be found in the `Clean`
|
||||
/// implementation for `AssociatedType`
|
||||
fn filter_non_trait_generics(trait_did: ast::DefId, mut g: clean::Generics)
|
||||
-> clean::Generics {
|
||||
g.where_predicates.retain(|pred| {
|
||||
match *pred {
|
||||
clean::WherePredicate::BoundPredicate {
|
||||
ty: clean::QPath {
|
||||
self_type: box clean::Generic(ref s),
|
||||
trait_: box clean::ResolvedPath { did, .. },
|
||||
name: ref _name,
|
||||
}, ..
|
||||
} => *s != "Self" || did != trait_did,
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
return g;
|
||||
}
|
||||
|
||||
/// Supertrait bounds for a trait are also listed in the generics coming from
|
||||
/// the metadata for a crate, so we want to separate those out and create a new
|
||||
/// list of explicit supertrait bounds to render nicely.
|
||||
fn separate_supertrait_bounds(mut g: clean::Generics)
|
||||
-> (clean::Generics, Vec<clean::TyParamBound>) {
|
||||
let mut ty_bounds = Vec::new();
|
||||
g.where_predicates.retain(|pred| {
|
||||
match *pred {
|
||||
clean::WherePredicate::BoundPredicate {
|
||||
ty: clean::Generic(ref s),
|
||||
ref bounds
|
||||
} if *s == "Self" => {
|
||||
ty_bounds.extend(bounds.iter().cloned());
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
(g, ty_bounds)
|
||||
}
|
||||
|
@ -44,9 +44,10 @@ use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace};
|
||||
use rustc::middle::ty;
|
||||
use rustc::middle::stability;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::u32;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use core::DocContext;
|
||||
use doctree;
|
||||
@ -57,6 +58,7 @@ use visit_ast;
|
||||
pub static SCHEMA_VERSION: &'static str = "0.8.3";
|
||||
|
||||
mod inline;
|
||||
mod simplify;
|
||||
|
||||
// extract the stability index for a node from tcx, if possible
|
||||
fn get_stability(cx: &DocContext, def_id: ast::DefId) -> Option<Stability> {
|
||||
@ -119,6 +121,7 @@ pub struct Crate {
|
||||
pub module: Option<Item>,
|
||||
pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
|
||||
pub primitives: Vec<PrimitiveType>,
|
||||
pub external_traits: HashMap<ast::DefId, Trait>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
|
||||
@ -197,6 +200,8 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
|
||||
module: Some(module),
|
||||
externs: externs,
|
||||
primitives: primitives,
|
||||
external_traits: cx.external_traits.borrow_mut().take()
|
||||
.unwrap_or(HashMap::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -493,6 +498,35 @@ pub enum TyParamBound {
|
||||
TraitBound(PolyTrait, ast::TraitBoundModifier)
|
||||
}
|
||||
|
||||
impl TyParamBound {
|
||||
fn maybe_sized(cx: &DocContext) -> TyParamBound {
|
||||
use syntax::ast::TraitBoundModifier as TBM;
|
||||
let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx);
|
||||
if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
|
||||
*tbm = TBM::Maybe
|
||||
};
|
||||
sized_bound
|
||||
}
|
||||
|
||||
fn is_sized_bound(&self, cx: &DocContext) -> bool {
|
||||
use syntax::ast::TraitBoundModifier as TBM;
|
||||
if let Some(tcx) = cx.tcx_opt() {
|
||||
let sized_did = match tcx.lang_items.sized_trait() {
|
||||
Some(did) => did,
|
||||
None => return false
|
||||
};
|
||||
if let TyParamBound::TraitBound(PolyTrait {
|
||||
trait_: Type::ResolvedPath { did, .. }, ..
|
||||
}, TBM::None) = *self {
|
||||
if did == sized_did {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<TyParamBound> for ast::TyParamBound {
|
||||
fn clean(&self, cx: &DocContext) -> TyParamBound {
|
||||
match *self {
|
||||
@ -830,7 +864,9 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
|
||||
fn clean(&self, cx: &DocContext) -> Type {
|
||||
let trait_ = match self.trait_ref.clean(cx) {
|
||||
TyParamBound::TraitBound(t, _) => t.trait_,
|
||||
TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
|
||||
TyParamBound::RegionBound(_) => {
|
||||
panic!("cleaning a trait got a region")
|
||||
}
|
||||
};
|
||||
Type::QPath {
|
||||
name: self.item_name.clean(cx),
|
||||
@ -863,32 +899,13 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
|
||||
subst::ParamSpace) {
|
||||
fn clean(&self, cx: &DocContext) -> Generics {
|
||||
use std::collections::HashSet;
|
||||
use syntax::ast::TraitBoundModifier as TBM;
|
||||
use self::WherePredicate as WP;
|
||||
|
||||
fn has_sized_bound(bounds: &[TyParamBound], cx: &DocContext) -> bool {
|
||||
if let Some(tcx) = cx.tcx_opt() {
|
||||
let sized_did = match tcx.lang_items.sized_trait() {
|
||||
Some(did) => did,
|
||||
None => return false
|
||||
};
|
||||
for bound in bounds {
|
||||
if let TyParamBound::TraitBound(PolyTrait {
|
||||
trait_: Type::ResolvedPath { did, .. }, ..
|
||||
}, TBM::None) = *bound {
|
||||
if did == sized_did {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
let (gens, preds, space) = *self;
|
||||
|
||||
// Bounds in the type_params and lifetimes fields are repeated in the predicates
|
||||
// field (see rustc_typeck::collect::ty_generics), so remove them.
|
||||
// Bounds in the type_params and lifetimes fields are repeated in the
|
||||
// predicates field (see rustc_typeck::collect::ty_generics), so remove
|
||||
// them.
|
||||
let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
|
||||
tp.clean(cx)
|
||||
}).collect::<Vec<_>>();
|
||||
@ -898,33 +915,38 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
|
||||
srp.clean(cx)
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let where_predicates = preds.predicates.get_slice(space).to_vec().clean(cx);
|
||||
let mut where_predicates = preds.predicates.get_slice(space)
|
||||
.to_vec().clean(cx);
|
||||
|
||||
// Type parameters have a Sized bound by default unless removed with ?Sized.
|
||||
// Scan through the predicates and mark any type parameter with a Sized
|
||||
// bound, removing the bounds as we find them.
|
||||
// Type parameters and have a Sized bound by default unless removed with
|
||||
// ?Sized. Scan through the predicates and mark any type parameter with
|
||||
// a Sized bound, removing the bounds as we find them.
|
||||
//
|
||||
// Note that associated types also have a sized bound by default, but we
|
||||
// don't actually konw the set of associated types right here so that's
|
||||
// handled in cleaning associated types
|
||||
let mut sized_params = HashSet::new();
|
||||
let mut where_predicates = where_predicates.into_iter().filter_map(|pred| {
|
||||
if let WP::BoundPredicate { ty: Type::Generic(ref g), ref bounds } = pred {
|
||||
if has_sized_bound(&**bounds, cx) {
|
||||
sized_params.insert(g.clone());
|
||||
return None
|
||||
where_predicates.retain(|pred| {
|
||||
match *pred {
|
||||
WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
|
||||
if bounds.iter().any(|b| b.is_sized_bound(cx)) {
|
||||
sized_params.insert(g.clone());
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
Some(pred)
|
||||
}).collect::<Vec<_>>();
|
||||
});
|
||||
|
||||
// Finally, run through the type parameters again and insert a ?Sized unbound for
|
||||
// any we didn't find to be Sized.
|
||||
// Run through the type parameters again and insert a ?Sized
|
||||
// unbound for any we didn't find to be Sized.
|
||||
for tp in &stripped_typarams {
|
||||
if !sized_params.contains(&tp.name) {
|
||||
let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx);
|
||||
if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
|
||||
*tbm = TBM::Maybe
|
||||
};
|
||||
where_predicates.push(WP::BoundPredicate {
|
||||
ty: Type::Generic(tp.name.clone()),
|
||||
bounds: vec![sized_bound]
|
||||
bounds: vec![TyParamBound::maybe_sized(cx)],
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -934,9 +956,9 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
|
||||
// and instead see `where T: Foo + Bar + Sized + 'a`
|
||||
|
||||
Generics {
|
||||
type_params: stripped_typarams,
|
||||
type_params: simplify::ty_params(stripped_typarams),
|
||||
lifetimes: stripped_lifetimes,
|
||||
where_predicates: where_predicates
|
||||
where_predicates: simplify::where_clauses(cx, where_predicates),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1032,6 +1054,7 @@ pub struct Function {
|
||||
pub decl: FnDecl,
|
||||
pub generics: Generics,
|
||||
pub unsafety: ast::Unsafety,
|
||||
pub abi: abi::Abi
|
||||
}
|
||||
|
||||
impl Clean<Item> for doctree::Function {
|
||||
@ -1047,6 +1070,7 @@ impl Clean<Item> for doctree::Function {
|
||||
decl: self.decl.clean(cx),
|
||||
generics: self.generics.clean(cx),
|
||||
unsafety: self.unsafety,
|
||||
abi: self.abi,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -1274,6 +1298,35 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
let generics = (&self.generics, &self.predicates,
|
||||
subst::FnSpace).clean(cx);
|
||||
let decl = (self.def_id, &sig).clean(cx);
|
||||
let provided = match self.container {
|
||||
ty::ImplContainer(..) => false,
|
||||
ty::TraitContainer(did) => {
|
||||
ty::provided_trait_methods(cx.tcx(), did).iter().any(|m| {
|
||||
m.def_id == self.def_id
|
||||
})
|
||||
}
|
||||
};
|
||||
let inner = if provided {
|
||||
MethodItem(Method {
|
||||
unsafety: self.fty.unsafety,
|
||||
generics: generics,
|
||||
self_: self_,
|
||||
decl: decl,
|
||||
abi: self.fty.abi
|
||||
})
|
||||
} else {
|
||||
TyMethodItem(TyMethod {
|
||||
unsafety: self.fty.unsafety,
|
||||
generics: generics,
|
||||
self_: self_,
|
||||
decl: decl,
|
||||
abi: self.fty.abi
|
||||
})
|
||||
};
|
||||
|
||||
Item {
|
||||
name: Some(self.name.clean(cx)),
|
||||
visibility: Some(ast::Inherited),
|
||||
@ -1281,13 +1334,7 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> {
|
||||
def_id: self.def_id,
|
||||
attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
|
||||
source: Span::empty(),
|
||||
inner: TyMethodItem(TyMethod {
|
||||
unsafety: self.fty.unsafety,
|
||||
generics: (&self.generics, &self.predicates, subst::FnSpace).clean(cx),
|
||||
self_: self_,
|
||||
decl: (self.def_id, &sig).clean(cx),
|
||||
abi: self.fty.abi
|
||||
})
|
||||
inner: inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1365,6 +1412,7 @@ pub enum PrimitiveType {
|
||||
Slice,
|
||||
Array,
|
||||
PrimitiveTuple,
|
||||
PrimitiveRawPointer,
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
|
||||
@ -1380,6 +1428,21 @@ pub enum TypeKind {
|
||||
TypeTypedef,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn primitive_type(&self) -> Option<PrimitiveType> {
|
||||
match *self {
|
||||
Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
|
||||
Vector(..) | BorrowedRef{ type_: box Vector(..), .. } => Some(Slice),
|
||||
FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => {
|
||||
Some(Array)
|
||||
}
|
||||
Tuple(..) => Some(PrimitiveTuple),
|
||||
RawPointer(..) => Some(PrimitiveRawPointer),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType {
|
||||
fn from_str(s: &str) -> Option<PrimitiveType> {
|
||||
match s {
|
||||
@ -1401,6 +1464,7 @@ impl PrimitiveType {
|
||||
"array" => Some(Array),
|
||||
"slice" => Some(Slice),
|
||||
"tuple" => Some(PrimitiveTuple),
|
||||
"pointer" => Some(PrimitiveRawPointer),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -1446,6 +1510,7 @@ impl PrimitiveType {
|
||||
Array => "array",
|
||||
Slice => "slice",
|
||||
PrimitiveTuple => "tuple",
|
||||
PrimitiveRawPointer => "pointer",
|
||||
}
|
||||
}
|
||||
|
||||
@ -1587,17 +1652,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
|
||||
}
|
||||
ty::ty_tup(ref t) => Tuple(t.clean(cx)),
|
||||
|
||||
ty::ty_projection(ref data) => {
|
||||
let trait_ref = match data.trait_ref.clean(cx) {
|
||||
TyParamBound::TraitBound(t, _) => t.trait_,
|
||||
TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
|
||||
};
|
||||
Type::QPath {
|
||||
name: data.item_name.clean(cx),
|
||||
self_type: box data.trait_ref.self_ty().clean(cx),
|
||||
trait_: box trait_ref,
|
||||
}
|
||||
}
|
||||
ty::ty_projection(ref data) => data.clean(cx),
|
||||
|
||||
ty::ty_param(ref p) => Generic(token::get_name(p.name).to_string()),
|
||||
|
||||
@ -1871,6 +1926,22 @@ pub struct Path {
|
||||
pub segments: Vec<PathSegment>,
|
||||
}
|
||||
|
||||
impl Path {
|
||||
pub fn singleton(name: String) -> Path {
|
||||
Path {
|
||||
global: false,
|
||||
segments: vec![PathSegment {
|
||||
name: name,
|
||||
params: PathParameters::AngleBracketed {
|
||||
lifetimes: Vec::new(),
|
||||
types: Vec::new(),
|
||||
bindings: Vec::new()
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Path> for ast::Path {
|
||||
fn clean(&self, cx: &DocContext) -> Path {
|
||||
Path {
|
||||
@ -2262,7 +2333,14 @@ impl Clean<ViewListIdent> for ast::PathListItem {
|
||||
|
||||
impl Clean<Vec<Item>> for ast::ForeignMod {
|
||||
fn clean(&self, cx: &DocContext) -> Vec<Item> {
|
||||
self.items.clean(cx)
|
||||
let mut items = self.items.clean(cx);
|
||||
for item in &mut items {
|
||||
match item.inner {
|
||||
ForeignFunctionItem(ref mut f) => f.abi = self.abi,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
items
|
||||
}
|
||||
}
|
||||
|
||||
@ -2274,6 +2352,7 @@ impl Clean<Item> for ast::ForeignItem {
|
||||
decl: decl.clean(cx),
|
||||
generics: generics.clean(cx),
|
||||
unsafety: ast::Unsafety::Unsafe,
|
||||
abi: abi::Rust,
|
||||
})
|
||||
}
|
||||
ast::ForeignItemStatic(ref ty, mutbl) => {
|
||||
@ -2506,21 +2585,66 @@ impl Clean<Stability> for attr::Stability {
|
||||
|
||||
impl Clean<Item> for ty::AssociatedType {
|
||||
fn clean(&self, cx: &DocContext) -> Item {
|
||||
// When loading a cross-crate associated type, the bounds for this type
|
||||
// are actually located on the trait/impl itself, so we need to load
|
||||
// all of the generics from there and then look for bounds that are
|
||||
// applied to this associated type in question.
|
||||
let predicates = ty::lookup_predicates(cx.tcx(), self.container.id());
|
||||
let generics = match self.container {
|
||||
ty::TraitContainer(did) => {
|
||||
let def = ty::lookup_trait_def(cx.tcx(), did);
|
||||
(&def.generics, &predicates, subst::TypeSpace).clean(cx)
|
||||
}
|
||||
ty::ImplContainer(did) => {
|
||||
let ty = ty::lookup_item_type(cx.tcx(), did);
|
||||
(&ty.generics, &predicates, subst::TypeSpace).clean(cx)
|
||||
}
|
||||
};
|
||||
let my_name = self.name.clean(cx);
|
||||
let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
|
||||
let (name, self_type, trait_, bounds) = match *pred {
|
||||
WherePredicate::BoundPredicate {
|
||||
ty: QPath { ref name, ref self_type, ref trait_ },
|
||||
ref bounds
|
||||
} => (name, self_type, trait_, bounds),
|
||||
_ => return None,
|
||||
};
|
||||
if *name != my_name { return None }
|
||||
match **trait_ {
|
||||
ResolvedPath { did, .. } if did == self.container.id() => {}
|
||||
_ => return None,
|
||||
}
|
||||
match **self_type {
|
||||
Generic(ref s) if *s == "Self" => {}
|
||||
_ => return None,
|
||||
}
|
||||
Some(bounds)
|
||||
}).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>();
|
||||
|
||||
// Our Sized/?Sized bound didn't get handled when creating the generics
|
||||
// because we didn't actually get our whole set of bounds until just now
|
||||
// (some of them may have come from the trait). If we do have a sized
|
||||
// bound, we remove it, and if we don't then we add the `?Sized` bound
|
||||
// at the end.
|
||||
match bounds.iter().position(|b| b.is_sized_bound(cx)) {
|
||||
Some(i) => { bounds.remove(i); }
|
||||
None => bounds.push(TyParamBound::maybe_sized(cx)),
|
||||
}
|
||||
|
||||
Item {
|
||||
source: DUMMY_SP.clean(cx),
|
||||
name: Some(self.name.clean(cx)),
|
||||
attrs: Vec::new(),
|
||||
// FIXME(#20727): bounds are missing and need to be filled in from the
|
||||
// predicates on the trait itself
|
||||
inner: AssociatedTypeItem(vec![], None),
|
||||
visibility: None,
|
||||
attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
|
||||
inner: AssociatedTypeItem(bounds, None),
|
||||
visibility: self.vis.clean(cx),
|
||||
def_id: self.def_id,
|
||||
stability: None,
|
||||
stability: stability::lookup(cx.tcx(), self.def_id).clean(cx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Clean<Typedef> for (ty::TypeScheme<'a>, ty::GenericPredicates<'a>, ParamSpace) {
|
||||
impl<'a> Clean<Typedef> for (ty::TypeScheme<'a>, ty::GenericPredicates<'a>,
|
||||
ParamSpace) {
|
||||
fn clean(&self, cx: &DocContext) -> Typedef {
|
||||
let (ref ty_scheme, ref predicates, ps) = *self;
|
||||
Typedef {
|
||||
|
180
src/librustdoc/clean/simplify.rs
Normal file
180
src/librustdoc/clean/simplify.rs
Normal file
@ -0,0 +1,180 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Simplification of where clauses and parameter bounds into a prettier and
|
||||
//! more canonical form.
|
||||
//!
|
||||
//! Currently all cross-crate-inlined function use `middle::ty` to reconstruct
|
||||
//! the AST (e.g. see all of `clean::inline`), but this is not always a
|
||||
//! non-lossy transformation. The current format of storage for where clauses
|
||||
//! for functions and such is simply a list of predicates. One example of this
|
||||
//! is that the AST predicate of:
|
||||
//!
|
||||
//! where T: Trait<Foo=Bar>
|
||||
//!
|
||||
//! is encoded as:
|
||||
//!
|
||||
//! where T: Trait, <T as Trait>::Foo = Bar
|
||||
//!
|
||||
//! This module attempts to reconstruct the original where and/or parameter
|
||||
//! bounds by special casing scenarios such as these. Fun!
|
||||
|
||||
use std::mem;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rustc::middle::subst;
|
||||
use rustc::middle::ty;
|
||||
use syntax::ast;
|
||||
|
||||
use clean::PathParameters as PP;
|
||||
use clean::WherePredicate as WP;
|
||||
use clean::{self, Clean};
|
||||
use core::DocContext;
|
||||
|
||||
pub fn where_clauses(cx: &DocContext, clauses: Vec<WP>) -> Vec<WP> {
|
||||
// First, partition the where clause into its separate components
|
||||
let mut params = HashMap::new();
|
||||
let mut lifetimes = Vec::new();
|
||||
let mut equalities = Vec::new();
|
||||
let mut tybounds = Vec::new();
|
||||
for clause in clauses {
|
||||
match clause {
|
||||
WP::BoundPredicate { ty, bounds } => {
|
||||
match ty {
|
||||
clean::Generic(s) => params.entry(s).or_insert(Vec::new())
|
||||
.extend(bounds),
|
||||
t => tybounds.push((t, ty_bounds(bounds))),
|
||||
}
|
||||
}
|
||||
WP::RegionPredicate { lifetime, bounds } => {
|
||||
lifetimes.push((lifetime, bounds));
|
||||
}
|
||||
WP::EqPredicate { lhs, rhs } => equalities.push((lhs, rhs)),
|
||||
}
|
||||
}
|
||||
|
||||
// Simplify the type parameter bounds on all the generics
|
||||
let mut params = params.into_iter().map(|(k, v)| {
|
||||
(k, ty_bounds(v))
|
||||
}).collect::<HashMap<_, _>>();
|
||||
|
||||
// Look for equality predicates on associated types that can be merged into
|
||||
// general bound predicates
|
||||
equalities.retain(|&(ref lhs, ref rhs)| {
|
||||
let (self_, trait_, name) = match *lhs {
|
||||
clean::QPath { ref self_type, ref trait_, ref name } => {
|
||||
(self_type, trait_, name)
|
||||
}
|
||||
_ => return true,
|
||||
};
|
||||
let generic = match **self_ {
|
||||
clean::Generic(ref s) => s,
|
||||
_ => return true,
|
||||
};
|
||||
let trait_did = match **trait_ {
|
||||
clean::ResolvedPath { did, .. } => did,
|
||||
_ => return true,
|
||||
};
|
||||
let bounds = match params.get_mut(generic) {
|
||||
Some(bound) => bound,
|
||||
None => return true,
|
||||
};
|
||||
!bounds.iter_mut().any(|b| {
|
||||
let trait_ref = match *b {
|
||||
clean::TraitBound(ref mut tr, _) => tr,
|
||||
clean::RegionBound(..) => return false,
|
||||
};
|
||||
let (did, path) = match trait_ref.trait_ {
|
||||
clean::ResolvedPath { did, ref mut path, ..} => (did, path),
|
||||
_ => return false,
|
||||
};
|
||||
// If this QPath's trait `trait_did` is the same as, or a supertrait
|
||||
// of, the bound's trait `did` then we can keep going, otherwise
|
||||
// this is just a plain old equality bound.
|
||||
if !trait_is_same_or_supertrait(cx, did, trait_did) {
|
||||
return false
|
||||
}
|
||||
let last = path.segments.last_mut().unwrap();
|
||||
match last.params {
|
||||
PP::AngleBracketed { ref mut bindings, .. } => {
|
||||
bindings.push(clean::TypeBinding {
|
||||
name: name.clone(),
|
||||
ty: rhs.clone(),
|
||||
});
|
||||
}
|
||||
PP::Parenthesized { ref mut output, .. } => {
|
||||
assert!(output.is_none());
|
||||
*output = Some(rhs.clone());
|
||||
}
|
||||
};
|
||||
true
|
||||
})
|
||||
});
|
||||
|
||||
// And finally, let's reassemble everything
|
||||
let mut clauses = Vec::new();
|
||||
clauses.extend(lifetimes.into_iter().map(|(lt, bounds)| {
|
||||
WP::RegionPredicate { lifetime: lt, bounds: bounds }
|
||||
}));
|
||||
clauses.extend(params.into_iter().map(|(k, v)| {
|
||||
WP::BoundPredicate {
|
||||
ty: clean::Generic(k),
|
||||
bounds: v,
|
||||
}
|
||||
}));
|
||||
clauses.extend(tybounds.into_iter().map(|(ty, bounds)| {
|
||||
WP::BoundPredicate { ty: ty, bounds: bounds }
|
||||
}));
|
||||
clauses.extend(equalities.into_iter().map(|(lhs, rhs)| {
|
||||
WP::EqPredicate { lhs: lhs, rhs: rhs }
|
||||
}));
|
||||
clauses
|
||||
}
|
||||
|
||||
pub fn ty_params(mut params: Vec<clean::TyParam>) -> Vec<clean::TyParam> {
|
||||
for param in params.iter_mut() {
|
||||
param.bounds = ty_bounds(mem::replace(&mut param.bounds, Vec::new()));
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
fn ty_bounds(bounds: Vec<clean::TyParamBound>) -> Vec<clean::TyParamBound> {
|
||||
bounds
|
||||
}
|
||||
|
||||
fn trait_is_same_or_supertrait(cx: &DocContext, child: ast::DefId,
|
||||
trait_: ast::DefId) -> bool {
|
||||
if child == trait_ {
|
||||
return true
|
||||
}
|
||||
let def = ty::lookup_trait_def(cx.tcx(), child);
|
||||
let predicates = ty::lookup_predicates(cx.tcx(), child);
|
||||
let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx);
|
||||
generics.where_predicates.iter().filter_map(|pred| {
|
||||
match *pred {
|
||||
clean::WherePredicate::BoundPredicate {
|
||||
ty: clean::Generic(ref s),
|
||||
ref bounds
|
||||
} if *s == "Self" => Some(bounds),
|
||||
_ => None,
|
||||
}
|
||||
}).flat_map(|bounds| bounds.iter()).any(|bound| {
|
||||
let poly_trait = match *bound {
|
||||
clean::TraitBound(ref t, _) => t,
|
||||
_ => return false,
|
||||
};
|
||||
match poly_trait.trait_ {
|
||||
clean::ResolvedPath { did, .. } => {
|
||||
trait_is_same_or_supertrait(cx, did, trait_)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
@ -75,7 +75,6 @@ pub struct CrateAnalysis {
|
||||
pub exported_items: privacy::ExportedItems,
|
||||
pub public_items: privacy::PublicItems,
|
||||
pub external_paths: ExternalPaths,
|
||||
pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
|
||||
pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
|
||||
pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
|
||||
}
|
||||
@ -155,7 +154,6 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
|
||||
exported_items: exported_items,
|
||||
public_items: public_items,
|
||||
external_paths: RefCell::new(None),
|
||||
external_traits: RefCell::new(None),
|
||||
external_typarams: RefCell::new(None),
|
||||
inlined: RefCell::new(None),
|
||||
};
|
||||
@ -168,8 +166,6 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
|
||||
|
||||
let external_paths = ctxt.external_paths.borrow_mut().take();
|
||||
*analysis.external_paths.borrow_mut() = external_paths;
|
||||
let map = ctxt.external_traits.borrow_mut().take();
|
||||
*analysis.external_traits.borrow_mut() = map;
|
||||
let map = ctxt.external_typarams.borrow_mut().take();
|
||||
*analysis.external_typarams.borrow_mut() = map;
|
||||
let map = ctxt.inlined.borrow_mut().take();
|
||||
|
@ -15,6 +15,7 @@ pub use self::TypeBound::*;
|
||||
|
||||
use syntax;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::ast::{Ident, NodeId};
|
||||
@ -134,6 +135,7 @@ pub struct Function {
|
||||
pub unsafety: ast::Unsafety,
|
||||
pub whence: Span,
|
||||
pub generics: ast::Generics,
|
||||
pub abi: abi::Abi,
|
||||
}
|
||||
|
||||
pub struct Typedef {
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use clean::*;
|
||||
use std::iter::Extend;
|
||||
use std::collections::HashMap;
|
||||
use std::mem::{replace, swap};
|
||||
|
||||
pub trait DocFolder : Sized {
|
||||
@ -80,6 +80,13 @@ pub trait DocFolder : Sized {
|
||||
c.module = match replace(&mut c.module, None) {
|
||||
Some(module) => self.fold_item(module), None => None
|
||||
};
|
||||
let external_traits = replace(&mut c.external_traits, HashMap::new());
|
||||
c.external_traits = external_traits.into_iter().map(|(k, mut v)| {
|
||||
let items = replace(&mut v.items, Vec::new());
|
||||
v.items = items.into_iter().filter_map(|i| self.fold_item(i))
|
||||
.collect();
|
||||
(k, v)
|
||||
}).collect();
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
use std::fmt;
|
||||
use std::iter::repeat;
|
||||
|
||||
use syntax::abi::Abi;
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
|
||||
@ -54,6 +55,7 @@ pub struct WhereClause<'a>(pub &'a clean::Generics);
|
||||
pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]);
|
||||
/// Wrapper struct for emitting a comma-separated list of items
|
||||
pub struct CommaSep<'a, T: 'a>(pub &'a [T]);
|
||||
pub struct AbiSpace(pub Abi);
|
||||
|
||||
impl VisSpace {
|
||||
pub fn get(&self) -> Option<ast::Visibility> {
|
||||
@ -281,48 +283,46 @@ impl fmt::Display for clean::Path {
|
||||
}
|
||||
}
|
||||
|
||||
/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
|
||||
/// rendering function with the necessary arguments for linking to a local path.
|
||||
fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, p: &clean::Path,
|
||||
print_all: bool) -> fmt::Result {
|
||||
path(w, p, print_all,
|
||||
|cache, loc| {
|
||||
if ast_util::is_local(did) || cache.inlined.contains(&did) {
|
||||
Some(repeat("../").take(loc.len()).collect::<String>())
|
||||
} else {
|
||||
match cache.extern_locations[&did.krate] {
|
||||
render::Remote(ref s) => Some(s.to_string()),
|
||||
render::Local => {
|
||||
Some(repeat("../").take(loc.len()).collect::<String>())
|
||||
}
|
||||
render::Unknown => None,
|
||||
}
|
||||
}
|
||||
},
|
||||
|cache| {
|
||||
match cache.paths.get(&did) {
|
||||
None => None,
|
||||
Some(&(ref fqp, shortty)) => Some((fqp.clone(), shortty))
|
||||
}
|
||||
})
|
||||
pub fn href(did: ast::DefId) -> Option<(String, ItemType, Vec<String>)> {
|
||||
let cache = cache();
|
||||
let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
|
||||
let &(ref fqp, shortty) = match cache.paths.get(&did) {
|
||||
Some(p) => p,
|
||||
None => return None,
|
||||
};
|
||||
let mut url = if ast_util::is_local(did) || cache.inlined.contains(&did) {
|
||||
repeat("../").take(loc.len()).collect::<String>()
|
||||
} else {
|
||||
match cache.extern_locations[&did.krate] {
|
||||
render::Remote(ref s) => s.to_string(),
|
||||
render::Local => repeat("../").take(loc.len()).collect::<String>(),
|
||||
render::Unknown => return None,
|
||||
}
|
||||
};
|
||||
for component in &fqp[..fqp.len() - 1] {
|
||||
url.push_str(component);
|
||||
url.push_str("/");
|
||||
}
|
||||
match shortty {
|
||||
ItemType::Module => {
|
||||
url.push_str(fqp.last().unwrap());
|
||||
url.push_str("/index.html");
|
||||
}
|
||||
_ => {
|
||||
url.push_str(shortty.to_static_str());
|
||||
url.push_str(".");
|
||||
url.push_str(fqp.last().unwrap());
|
||||
url.push_str(".html");
|
||||
}
|
||||
}
|
||||
Some((url, shortty, fqp.to_vec()))
|
||||
}
|
||||
|
||||
fn path<F, G>(w: &mut fmt::Formatter,
|
||||
path: &clean::Path,
|
||||
print_all: bool,
|
||||
root: F,
|
||||
info: G)
|
||||
-> fmt::Result where
|
||||
F: FnOnce(&render::Cache, &[String]) -> Option<String>,
|
||||
G: FnOnce(&render::Cache) -> Option<(Vec<String>, ItemType)>,
|
||||
{
|
||||
// The generics will get written to both the title and link
|
||||
/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
|
||||
/// rendering function with the necessary arguments for linking to a local path.
|
||||
fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, path: &clean::Path,
|
||||
print_all: bool) -> fmt::Result {
|
||||
let last = path.segments.last().unwrap();
|
||||
let generics = format!("{}", last.params);
|
||||
|
||||
let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
|
||||
let cache = cache();
|
||||
let abs_root = root(&*cache, &loc);
|
||||
let rel_root = match &*path.segments[0].name {
|
||||
"self" => Some("./".to_string()),
|
||||
_ => None,
|
||||
@ -334,8 +334,7 @@ fn path<F, G>(w: &mut fmt::Formatter,
|
||||
Some(root) => {
|
||||
let mut root = String::from_str(&root);
|
||||
for seg in &path.segments[..amt] {
|
||||
if "super" == seg.name ||
|
||||
"self" == seg.name {
|
||||
if "super" == seg.name || "self" == seg.name {
|
||||
try!(write!(w, "{}::", seg.name));
|
||||
} else {
|
||||
root.push_str(&seg.name);
|
||||
@ -355,37 +354,14 @@ fn path<F, G>(w: &mut fmt::Formatter,
|
||||
}
|
||||
}
|
||||
|
||||
match info(&*cache) {
|
||||
// This is a documented path, link to it!
|
||||
Some((ref fqp, shortty)) if abs_root.is_some() => {
|
||||
let mut url = String::from_str(&abs_root.unwrap());
|
||||
let to_link = &fqp[..fqp.len() - 1];
|
||||
for component in to_link {
|
||||
url.push_str(component);
|
||||
url.push_str("/");
|
||||
}
|
||||
match shortty {
|
||||
ItemType::Module => {
|
||||
url.push_str(fqp.last().unwrap());
|
||||
url.push_str("/index.html");
|
||||
}
|
||||
_ => {
|
||||
url.push_str(shortty.to_static_str());
|
||||
url.push_str(".");
|
||||
url.push_str(fqp.last().unwrap());
|
||||
url.push_str(".html");
|
||||
}
|
||||
}
|
||||
|
||||
match href(did) {
|
||||
Some((url, shortty, fqp)) => {
|
||||
try!(write!(w, "<a class='{}' href='{}' title='{}'>{}</a>",
|
||||
shortty, url, fqp.connect("::"), last.name));
|
||||
}
|
||||
|
||||
_ => {
|
||||
try!(write!(w, "{}", last.name));
|
||||
}
|
||||
_ => try!(write!(w, "{}", last.name)),
|
||||
}
|
||||
try!(write!(w, "{}", generics));
|
||||
try!(write!(w, "{}", last.params));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -491,7 +467,8 @@ impl fmt::Display for clean::Type {
|
||||
}
|
||||
clean::Bottom => f.write_str("!"),
|
||||
clean::RawPointer(m, ref t) => {
|
||||
write!(f, "*{}{}", RawMutableSpace(m), **t)
|
||||
primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer,
|
||||
&format!("*{}{}", RawMutableSpace(m), **t))
|
||||
}
|
||||
clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
|
||||
let lt = match *l {
|
||||
@ -527,6 +504,29 @@ impl fmt::Display for clean::Type {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
// It's pretty unsightly to look at `<A as B>::C` in output, and
|
||||
// we've got hyperlinking on our side, so try to avoid longer
|
||||
// notation as much as possible by making `C` a hyperlink to trait
|
||||
// `B` to disambiguate.
|
||||
//
|
||||
// FIXME: this is still a lossy conversion and there should probably
|
||||
// be a better way of representing this in general? Most of
|
||||
// the ugliness comes from inlining across crates where
|
||||
// everything comes in as a fully resolved QPath (hard to
|
||||
// look at).
|
||||
clean::QPath {
|
||||
ref name,
|
||||
ref self_type,
|
||||
trait_: box clean::ResolvedPath { did, ref typarams, .. },
|
||||
} => {
|
||||
try!(write!(f, "{}::", self_type));
|
||||
let path = clean::Path::singleton(name.clone());
|
||||
try!(resolved_path(f, did, &path, false));
|
||||
|
||||
// FIXME: `typarams` are not rendered, and this seems bad?
|
||||
drop(typarams);
|
||||
Ok(())
|
||||
}
|
||||
clean::QPath { ref name, ref self_type, ref trait_ } => {
|
||||
write!(f, "<{} as {}>::{}", self_type, trait_, name)
|
||||
}
|
||||
@ -661,17 +661,7 @@ impl fmt::Display for clean::ViewListIdent {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.source {
|
||||
Some(did) => {
|
||||
let path = clean::Path {
|
||||
global: false,
|
||||
segments: vec!(clean::PathSegment {
|
||||
name: self.name.clone(),
|
||||
params: clean::PathParameters::AngleBracketed {
|
||||
lifetimes: Vec::new(),
|
||||
types: Vec::new(),
|
||||
bindings: Vec::new()
|
||||
}
|
||||
})
|
||||
};
|
||||
let path = clean::Path::singleton(self.name.clone());
|
||||
resolved_path(f, did, &path, false)
|
||||
}
|
||||
_ => write!(f, "{}", self.name),
|
||||
@ -703,6 +693,16 @@ impl fmt::Display for RawMutableSpace {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for AbiSpace {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.0 {
|
||||
Abi::Rust => Ok(()),
|
||||
Abi::C => write!(f, "extern "),
|
||||
abi => write!(f, "extern {} ", abi),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for Stability<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let Stability(stab) = *self;
|
||||
|
@ -29,9 +29,10 @@
|
||||
|
||||
use libc;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::ffi::CString;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::default::Default;
|
||||
use std::ffi::CString;
|
||||
use std::fmt;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
@ -182,7 +183,9 @@ impl hoedown_buffer {
|
||||
/// left as-is.)
|
||||
fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
|
||||
let trimmed = s.trim();
|
||||
if trimmed.starts_with("# ") {
|
||||
if trimmed == "#" {
|
||||
Some("")
|
||||
} else if trimmed.starts_with("# ") {
|
||||
Some(&trimmed[2..])
|
||||
} else {
|
||||
None
|
||||
@ -244,7 +247,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
|
||||
stripped_filtered_line(l).unwrap_or(l)
|
||||
}).collect::<Vec<&str>>().connect("\n");
|
||||
let krate = krate.as_ref().map(|s| &**s);
|
||||
let test = test::maketest(&test, krate, false, false, true);
|
||||
let test = test::maketest(&test, krate, false,
|
||||
&Default::default());
|
||||
s.push_str(&format!("<span class='rusttest'>{}</span>", Escape(&test)));
|
||||
});
|
||||
s.push_str(&highlight::highlight(&text,
|
||||
|
@ -44,6 +44,7 @@ use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
use std::io::{self, BufWriter, BufReader};
|
||||
use std::iter::repeat;
|
||||
use std::mem;
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::str;
|
||||
use std::sync::Arc;
|
||||
@ -61,7 +62,7 @@ use clean;
|
||||
use doctree;
|
||||
use fold::DocFolder;
|
||||
use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace, Stability};
|
||||
use html::format::{ConciseStability, TyParamBounds, WhereClause};
|
||||
use html::format::{ConciseStability, TyParamBounds, WhereClause, href, AbiSpace};
|
||||
use html::highlight;
|
||||
use html::item_type::ItemType;
|
||||
use html::layout;
|
||||
@ -136,6 +137,14 @@ pub struct Impl {
|
||||
pub stability: Option<clean::Stability>,
|
||||
}
|
||||
|
||||
impl Impl {
|
||||
fn trait_did(&self) -> Option<ast::DefId> {
|
||||
self.impl_.trait_.as_ref().and_then(|tr| {
|
||||
if let clean::ResolvedPath { did, .. } = *tr {Some(did)} else {None}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// This cache is used to store information about the `clean::Crate` being
|
||||
/// rendered in order to provide more useful documentation. This contains
|
||||
/// information like all implementors of a trait, all traits a type implements,
|
||||
@ -276,7 +285,9 @@ impl fmt::Display for IndexItemFunctionType {
|
||||
return write!(f, "null")
|
||||
}
|
||||
|
||||
let inputs: Vec<String> = self.inputs.iter().map(|ref t| format!("{}", t)).collect();
|
||||
let inputs: Vec<String> = self.inputs.iter().map(|ref t| {
|
||||
format!("{}", t)
|
||||
}).collect();
|
||||
try!(write!(f, "{{\"inputs\":[{}],\"output\":", inputs.connect(",")));
|
||||
|
||||
match self.output {
|
||||
@ -383,9 +394,7 @@ pub fn run(mut krate: clean::Crate,
|
||||
privmod: false,
|
||||
public_items: public_items,
|
||||
orphan_methods: Vec::new(),
|
||||
traits: analysis.as_ref().map(|a| {
|
||||
a.external_traits.borrow_mut().take().unwrap()
|
||||
}).unwrap_or(HashMap::new()),
|
||||
traits: mem::replace(&mut krate.external_traits, HashMap::new()),
|
||||
typarams: analysis.as_ref().map(|a| {
|
||||
a.external_typarams.borrow_mut().take().unwrap()
|
||||
}).unwrap_or(HashMap::new()),
|
||||
@ -911,9 +920,10 @@ impl DocFolder for Cache {
|
||||
let path = match self.paths.get(&did) {
|
||||
Some(&(_, ItemType::Trait)) =>
|
||||
Some(&self.stack[..self.stack.len() - 1]),
|
||||
// The current stack not necessarily has correlation for
|
||||
// where the type was defined. On the other hand,
|
||||
// `paths` always has the right information if present.
|
||||
// The current stack not necessarily has correlation
|
||||
// for where the type was defined. On the other
|
||||
// hand, `paths` always has the right
|
||||
// information if present.
|
||||
Some(&(ref fqp, ItemType::Struct)) |
|
||||
Some(&(ref fqp, ItemType::Enum)) =>
|
||||
Some(&fqp[..fqp.len() - 1]),
|
||||
@ -1015,7 +1025,16 @@ impl DocFolder for Cache {
|
||||
self.parent_stack.push(did);
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
ref t => {
|
||||
match t.primitive_type() {
|
||||
Some(prim) => {
|
||||
let did = ast_util::local_def(prim.to_node_id());
|
||||
self.parent_stack.push(did);
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => false
|
||||
@ -1027,10 +1046,6 @@ impl DocFolder for Cache {
|
||||
Some(item) => {
|
||||
match item {
|
||||
clean::Item{ attrs, inner: clean::ImplItem(i), .. } => {
|
||||
use clean::{Primitive, Vector, ResolvedPath, BorrowedRef};
|
||||
use clean::PrimitiveType::{Array, Slice, PrimitiveTuple};
|
||||
use clean::{FixedVector, Tuple};
|
||||
|
||||
// extract relevant documentation for this impl
|
||||
let dox = match attrs.into_iter().find(|a| {
|
||||
match *a {
|
||||
@ -1048,37 +1063,18 @@ impl DocFolder for Cache {
|
||||
// Figure out the id of this impl. This may map to a
|
||||
// primitive rather than always to a struct/enum.
|
||||
let did = match i.for_ {
|
||||
ResolvedPath { did, .. } => Some(did),
|
||||
|
||||
// References to primitives are picked up as well to
|
||||
// recognize implementations for &str, this may not
|
||||
// be necessary in a DST world.
|
||||
Primitive(p) |
|
||||
BorrowedRef { type_: box Primitive(p), ..} =>
|
||||
{
|
||||
Some(ast_util::local_def(p.to_node_id()))
|
||||
clean::ResolvedPath { did, .. } |
|
||||
clean::BorrowedRef {
|
||||
type_: box clean::ResolvedPath { did, .. }, ..
|
||||
} => {
|
||||
Some(did)
|
||||
}
|
||||
|
||||
FixedVector(..) |
|
||||
BorrowedRef { type_: box FixedVector(..), .. } =>
|
||||
{
|
||||
Some(ast_util::local_def(Array.to_node_id()))
|
||||
ref t => {
|
||||
t.primitive_type().map(|p| {
|
||||
ast_util::local_def(p.to_node_id())
|
||||
})
|
||||
}
|
||||
|
||||
// In a DST world, we may only need Vector, but for now we
|
||||
// also pick up borrowed references
|
||||
Vector(..) |
|
||||
BorrowedRef{ type_: box Vector(..), .. } =>
|
||||
{
|
||||
Some(ast_util::local_def(Slice.to_node_id()))
|
||||
}
|
||||
|
||||
Tuple(..) => {
|
||||
let id = PrimitiveTuple.to_node_id();
|
||||
Some(ast_util::local_def(id))
|
||||
}
|
||||
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(did) = did {
|
||||
@ -1347,7 +1343,9 @@ impl Context {
|
||||
fn ignore_private_item(&self, it: &clean::Item) -> bool {
|
||||
match it.inner {
|
||||
clean::ModuleItem(ref m) => {
|
||||
(m.items.len() == 0 && it.doc_value().is_none()) ||
|
||||
(m.items.len() == 0 &&
|
||||
it.doc_value().is_none() &&
|
||||
it.visibility != Some(ast::Public)) ||
|
||||
(self.passes.contains("strip-private") && it.visibility != Some(ast::Public))
|
||||
}
|
||||
clean::PrimitiveItem(..) => it.visibility != Some(ast::Public),
|
||||
@ -1723,10 +1721,11 @@ fn item_static(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
|
||||
fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
f: &clean::Function) -> fmt::Result {
|
||||
try!(write!(w, "<pre class='rust fn'>{vis}{unsafety}fn \
|
||||
try!(write!(w, "<pre class='rust fn'>{vis}{unsafety}{abi}fn \
|
||||
{name}{generics}{decl}{where_clause}</pre>",
|
||||
vis = VisSpace(it.visibility),
|
||||
unsafety = UnsafetySpace(f.unsafety),
|
||||
abi = AbiSpace(f.abi),
|
||||
name = it.name.as_ref().unwrap(),
|
||||
generics = f.generics,
|
||||
where_clause = WhereClause(&f.generics),
|
||||
@ -1773,7 +1772,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||
try!(write!(w, "{{\n"));
|
||||
for t in &types {
|
||||
try!(write!(w, " "));
|
||||
try!(render_method(w, t));
|
||||
try!(render_method(w, t, MethodLink::Anchor));
|
||||
try!(write!(w, ";\n"));
|
||||
}
|
||||
if types.len() > 0 && required.len() > 0 {
|
||||
@ -1781,7 +1780,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||
}
|
||||
for m in &required {
|
||||
try!(write!(w, " "));
|
||||
try!(render_method(w, m));
|
||||
try!(render_method(w, m, MethodLink::Anchor));
|
||||
try!(write!(w, ";\n"));
|
||||
}
|
||||
if required.len() > 0 && provided.len() > 0 {
|
||||
@ -1789,7 +1788,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||
}
|
||||
for m in &provided {
|
||||
try!(write!(w, " "));
|
||||
try!(render_method(w, m));
|
||||
try!(render_method(w, m, MethodLink::Anchor));
|
||||
try!(write!(w, " {{ ... }}\n"));
|
||||
}
|
||||
try!(write!(w, "}}"));
|
||||
@ -1805,7 +1804,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||
shortty(m),
|
||||
*m.name.as_ref().unwrap(),
|
||||
ConciseStability(&m.stability)));
|
||||
try!(render_method(w, m));
|
||||
try!(render_method(w, m, MethodLink::Anchor));
|
||||
try!(write!(w, "</code></h3>"));
|
||||
try!(document(w, m));
|
||||
Ok(())
|
||||
@ -1844,6 +1843,9 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
||||
try!(write!(w, "</div>"));
|
||||
}
|
||||
|
||||
// If there are methods directly on this trait object, render them here.
|
||||
try!(render_methods(w, it));
|
||||
|
||||
let cache = cache();
|
||||
try!(write!(w, "
|
||||
<h2 id='implementors'>Implementors</h2>
|
||||
@ -1889,14 +1891,23 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
|
||||
fn render_method(w: &mut fmt::Formatter, meth: &clean::Item,
|
||||
link: MethodLink) -> fmt::Result {
|
||||
fn method(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
unsafety: ast::Unsafety, abi: abi::Abi,
|
||||
g: &clean::Generics, selfty: &clean::SelfTy,
|
||||
d: &clean::FnDecl) -> fmt::Result {
|
||||
d: &clean::FnDecl, link: MethodLink) -> fmt::Result {
|
||||
use syntax::abi::Abi;
|
||||
|
||||
write!(w, "{}{}fn <a href='#{ty}.{name}' class='fnname'>{name}</a>\
|
||||
let name = it.name.as_ref().unwrap();
|
||||
let anchor = format!("#{}.{}", shortty(it), name);
|
||||
let href = match link {
|
||||
MethodLink::Anchor => anchor,
|
||||
MethodLink::GotoSource(did) => {
|
||||
href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
|
||||
}
|
||||
};
|
||||
write!(w, "{}{}fn <a href='{href}' class='fnname'>{name}</a>\
|
||||
{generics}{decl}{where_clause}",
|
||||
match unsafety {
|
||||
ast::Unsafety::Unsafe => "unsafe ",
|
||||
@ -1906,18 +1917,20 @@ fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
|
||||
Abi::Rust => String::new(),
|
||||
a => format!("extern {} ", a.to_string())
|
||||
},
|
||||
ty = shortty(it),
|
||||
name = it.name.as_ref().unwrap(),
|
||||
href = href,
|
||||
name = name,
|
||||
generics = *g,
|
||||
decl = Method(selfty, d),
|
||||
where_clause = WhereClause(g))
|
||||
}
|
||||
match meth.inner {
|
||||
clean::TyMethodItem(ref m) => {
|
||||
method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl)
|
||||
method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl,
|
||||
link)
|
||||
}
|
||||
clean::MethodItem(ref m) => {
|
||||
method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl)
|
||||
method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl,
|
||||
link)
|
||||
}
|
||||
clean::AssociatedTypeItem(ref bounds, ref default) => {
|
||||
assoc_type(w, meth, bounds, default)
|
||||
@ -2144,69 +2157,73 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum MethodLink {
|
||||
Anchor,
|
||||
GotoSource(ast::DefId),
|
||||
}
|
||||
|
||||
fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
|
||||
match cache().impls.get(&it.def_id) {
|
||||
Some(v) => {
|
||||
let (non_trait, traits): (Vec<_>, _) = v.iter().cloned()
|
||||
.partition(|i| i.impl_.trait_.is_none());
|
||||
if non_trait.len() > 0 {
|
||||
try!(write!(w, "<h2 id='methods'>Methods</h2>"));
|
||||
for i in &non_trait {
|
||||
try!(render_impl(w, i));
|
||||
}
|
||||
}
|
||||
if traits.len() > 0 {
|
||||
try!(write!(w, "<h2 id='implementations'>Trait \
|
||||
Implementations</h2>"));
|
||||
let (derived, manual): (Vec<_>, _) = traits.into_iter()
|
||||
.partition(|i| i.impl_.derived);
|
||||
for i in &manual {
|
||||
try!(render_impl(w, i));
|
||||
}
|
||||
if derived.len() > 0 {
|
||||
try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \
|
||||
</h3>"));
|
||||
for i in &derived {
|
||||
try!(render_impl(w, i));
|
||||
}
|
||||
}
|
||||
let v = match cache().impls.get(&it.def_id) {
|
||||
Some(v) => v.clone(),
|
||||
None => return Ok(()),
|
||||
};
|
||||
let (non_trait, traits): (Vec<_>, _) = v.into_iter()
|
||||
.partition(|i| i.impl_.trait_.is_none());
|
||||
if non_trait.len() > 0 {
|
||||
try!(write!(w, "<h2 id='methods'>Methods</h2>"));
|
||||
for i in &non_trait {
|
||||
try!(render_impl(w, i, MethodLink::Anchor));
|
||||
}
|
||||
}
|
||||
if traits.len() > 0 {
|
||||
try!(write!(w, "<h2 id='implementations'>Trait \
|
||||
Implementations</h2>"));
|
||||
let (derived, manual): (Vec<_>, _) = traits.into_iter()
|
||||
.partition(|i| i.impl_.derived);
|
||||
for i in &manual {
|
||||
let did = i.trait_did().unwrap();
|
||||
try!(render_impl(w, i, MethodLink::GotoSource(did)));
|
||||
}
|
||||
if derived.len() > 0 {
|
||||
try!(write!(w, "<h3 id='derived_implementations'>\
|
||||
Derived Implementations \
|
||||
</h3>"));
|
||||
for i in &derived {
|
||||
let did = i.trait_did().unwrap();
|
||||
try!(render_impl(w, i, MethodLink::GotoSource(did)));
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
|
||||
fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink)
|
||||
-> fmt::Result {
|
||||
try!(write!(w, "<h3 class='impl'>{}<code>impl{} ",
|
||||
ConciseStability(&i.stability),
|
||||
i.impl_.generics));
|
||||
match i.impl_.polarity {
|
||||
Some(clean::ImplPolarity::Negative) => try!(write!(w, "!")),
|
||||
_ => {}
|
||||
if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity {
|
||||
try!(write!(w, "!"));
|
||||
}
|
||||
match i.impl_.trait_ {
|
||||
Some(ref ty) => try!(write!(w, "{} for ", *ty)),
|
||||
None => {}
|
||||
if let Some(ref ty) = i.impl_.trait_ {
|
||||
try!(write!(w, "{} for ", *ty));
|
||||
}
|
||||
try!(write!(w, "{}{}</code></h3>", i.impl_.for_, WhereClause(&i.impl_.generics)));
|
||||
match i.dox {
|
||||
Some(ref dox) => {
|
||||
try!(write!(w, "<div class='docblock'>{}</div>",
|
||||
Markdown(dox)));
|
||||
}
|
||||
None => {}
|
||||
try!(write!(w, "{}{}</code></h3>", i.impl_.for_,
|
||||
WhereClause(&i.impl_.generics)));
|
||||
if let Some(ref dox) = i.dox {
|
||||
try!(write!(w, "<div class='docblock'>{}</div>", Markdown(dox)));
|
||||
}
|
||||
|
||||
fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item, dox: bool)
|
||||
-> fmt::Result {
|
||||
fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item,
|
||||
dox: bool, link: MethodLink) -> fmt::Result {
|
||||
match item.inner {
|
||||
clean::MethodItem(..) | clean::TyMethodItem(..) => {
|
||||
try!(write!(w, "<h4 id='method.{}' class='{}'>{}<code>",
|
||||
*item.name.as_ref().unwrap(),
|
||||
shortty(item),
|
||||
ConciseStability(&item.stability)));
|
||||
try!(render_method(w, item));
|
||||
try!(render_method(w, item, link));
|
||||
try!(write!(w, "</code></h4>\n"));
|
||||
}
|
||||
clean::TypedefItem(ref tydef) => {
|
||||
@ -2239,11 +2256,12 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
|
||||
}
|
||||
|
||||
try!(write!(w, "<div class='impl-items'>"));
|
||||
for trait_item in &i.impl_.items {
|
||||
try!(doctraititem(w, trait_item, true));
|
||||
for trait_item in i.impl_.items.iter() {
|
||||
try!(doctraititem(w, trait_item, true, link));
|
||||
}
|
||||
|
||||
fn render_default_methods(w: &mut fmt::Formatter,
|
||||
did: ast::DefId,
|
||||
t: &clean::Trait,
|
||||
i: &clean::Impl) -> fmt::Result {
|
||||
for trait_item in &t.items {
|
||||
@ -2253,7 +2271,8 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
|
||||
None => {}
|
||||
}
|
||||
|
||||
try!(doctraititem(w, trait_item, false));
|
||||
try!(doctraititem(w, trait_item, false,
|
||||
MethodLink::GotoSource(did)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -2262,17 +2281,10 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
|
||||
// default methods which weren't overridden in the implementation block.
|
||||
// FIXME: this also needs to be done for associated types, whenever defaults
|
||||
// for them work.
|
||||
match i.impl_.trait_ {
|
||||
Some(clean::ResolvedPath { did, .. }) => {
|
||||
try!({
|
||||
match cache().traits.get(&did) {
|
||||
Some(t) => try!(render_default_methods(w, t, &i.impl_)),
|
||||
None => {}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ {
|
||||
if let Some(t) = cache().traits.get(&did) {
|
||||
try!(render_default_methods(w, did, t, &i.impl_));
|
||||
}
|
||||
Some(..) | None => {}
|
||||
}
|
||||
try!(write!(w, "</div>"));
|
||||
Ok(())
|
||||
|
@ -8,9 +8,10 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::default::Default;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::path::{PathBuf, Path};
|
||||
|
||||
use core;
|
||||
@ -23,7 +24,7 @@ use externalfiles::ExternalHtml;
|
||||
use html::escape::Escape;
|
||||
use html::markdown;
|
||||
use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, reset_headers};
|
||||
use test::Collector;
|
||||
use test::{TestOptions, Collector};
|
||||
|
||||
/// Separate any lines at the start of the file that begin with `%`.
|
||||
fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
|
||||
@ -58,7 +59,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
|
||||
let input_str = load_or_return!(input, 1, 2);
|
||||
let playground = matches.opt_str("markdown-playground-url");
|
||||
if playground.is_some() {
|
||||
markdown::PLAYGROUND_KRATE.with(|s| { *s.borrow_mut() = None; });
|
||||
markdown::PLAYGROUND_KRATE.with(|s| { *s.borrow_mut() = Some(None); });
|
||||
}
|
||||
let playground = playground.unwrap_or("".to_string());
|
||||
|
||||
@ -143,7 +144,10 @@ pub fn test(input: &str, libs: SearchPaths, externs: core::Externs,
|
||||
mut test_args: Vec<String>) -> isize {
|
||||
let input_str = load_or_return!(input, 1, 2);
|
||||
|
||||
let mut collector = Collector::new(input.to_string(), libs, externs, true, false);
|
||||
let mut opts = TestOptions::default();
|
||||
opts.no_crate_inject = true;
|
||||
let mut collector = Collector::new(input.to_string(), libs, externs,
|
||||
true, opts);
|
||||
find_testable_code(&input_str, &mut collector);
|
||||
test_args.insert(0, "rustdoctest".to_string());
|
||||
testing::test_main(&test_args, collector.tests);
|
||||
|
@ -38,6 +38,12 @@ use html::markdown;
|
||||
use passes;
|
||||
use visit_ast::RustdocVisitor;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct TestOptions {
|
||||
pub no_crate_inject: bool,
|
||||
pub attrs: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn run(input: &str,
|
||||
cfgs: Vec<String>,
|
||||
libs: SearchPaths,
|
||||
@ -75,7 +81,7 @@ pub fn run(input: &str,
|
||||
"rustdoc-test", None)
|
||||
.expect("phase_2_configure_and_expand aborted in rustdoc!");
|
||||
|
||||
let inject_crate = should_inject_crate(&krate);
|
||||
let opts = scrape_test_config(&krate);
|
||||
|
||||
let ctx = core::DocContext {
|
||||
krate: &krate,
|
||||
@ -102,7 +108,7 @@ pub fn run(input: &str,
|
||||
libs,
|
||||
externs,
|
||||
false,
|
||||
inject_crate);
|
||||
opts);
|
||||
collector.fold_crate(krate);
|
||||
|
||||
test_args.insert(0, "rustdoctest".to_string());
|
||||
@ -113,41 +119,44 @@ pub fn run(input: &str,
|
||||
}
|
||||
|
||||
// Look for #![doc(test(no_crate_inject))], used by crates in the std facade
|
||||
fn should_inject_crate(krate: &::syntax::ast::Crate) -> bool {
|
||||
fn scrape_test_config(krate: &::syntax::ast::Crate) -> TestOptions {
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::print::pprust;
|
||||
|
||||
let mut inject_crate = true;
|
||||
let mut opts = TestOptions {
|
||||
no_crate_inject: false,
|
||||
attrs: Vec::new(),
|
||||
};
|
||||
|
||||
for attr in &krate.attrs {
|
||||
if attr.check_name("doc") {
|
||||
for list in attr.meta_item_list().into_iter() {
|
||||
for attr in list {
|
||||
if attr.check_name("test") {
|
||||
for list in attr.meta_item_list().into_iter() {
|
||||
for attr in list {
|
||||
if attr.check_name("no_crate_inject") {
|
||||
inject_crate = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let attrs = krate.attrs.iter().filter(|a| a.check_name("doc"))
|
||||
.filter_map(|a| a.meta_item_list())
|
||||
.flat_map(|l| l.iter())
|
||||
.filter(|a| a.check_name("test"))
|
||||
.filter_map(|a| a.meta_item_list())
|
||||
.flat_map(|l| l.iter());
|
||||
for attr in attrs {
|
||||
if attr.check_name("no_crate_inject") {
|
||||
opts.no_crate_inject = true;
|
||||
}
|
||||
if attr.check_name("attr") {
|
||||
if let Some(l) = attr.meta_item_list() {
|
||||
for item in l {
|
||||
opts.attrs.push(pprust::meta_item_to_string(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inject_crate;
|
||||
return opts;
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
fn runtest(test: &str, cratename: &str, libs: SearchPaths,
|
||||
externs: core::Externs,
|
||||
should_panic: bool, no_run: bool, as_test_harness: bool,
|
||||
inject_crate: bool) {
|
||||
opts: &TestOptions) {
|
||||
// the test harness wants its own `main` & top level functions, so
|
||||
// never wrap the test in `fn main() { ... }`
|
||||
let test = maketest(test, Some(cratename), true, as_test_harness,
|
||||
inject_crate);
|
||||
let test = maketest(test, Some(cratename), as_test_harness, opts);
|
||||
let input = config::Input::Str(test.to_string());
|
||||
|
||||
let sessopts = config::Options {
|
||||
@ -250,8 +259,8 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maketest(s: &str, cratename: Option<&str>, lints: bool,
|
||||
dont_insert_main: bool, inject_crate: bool) -> String {
|
||||
pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool,
|
||||
opts: &TestOptions) -> String {
|
||||
let (crate_attrs, everything_else) = partition_source(s);
|
||||
|
||||
let mut prog = String::new();
|
||||
@ -260,20 +269,18 @@ pub fn maketest(s: &str, cratename: Option<&str>, lints: bool,
|
||||
// are intended to be crate attributes.
|
||||
prog.push_str(&crate_attrs);
|
||||
|
||||
if lints {
|
||||
prog.push_str(r"
|
||||
#![allow(unused_variables, unused_assignments, unused_mut, unused_attributes, dead_code)]
|
||||
");
|
||||
// Next, any attributes for other aspects such as lints.
|
||||
for attr in &opts.attrs {
|
||||
prog.push_str(&format!("#![{}]\n", attr));
|
||||
}
|
||||
|
||||
// Don't inject `extern crate std` because it's already injected by the
|
||||
// compiler.
|
||||
if !s.contains("extern crate") && inject_crate {
|
||||
if !s.contains("extern crate") && !opts.no_crate_inject {
|
||||
match cratename {
|
||||
Some(cratename) => {
|
||||
if s.contains(cratename) {
|
||||
prog.push_str(&format!("extern crate {};\n",
|
||||
cratename));
|
||||
prog.push_str(&format!("extern crate {};\n", cratename));
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
@ -325,12 +332,12 @@ pub struct Collector {
|
||||
use_headers: bool,
|
||||
current_header: Option<String>,
|
||||
cratename: String,
|
||||
inject_crate: bool
|
||||
opts: TestOptions,
|
||||
}
|
||||
|
||||
impl Collector {
|
||||
pub fn new(cratename: String, libs: SearchPaths, externs: core::Externs,
|
||||
use_headers: bool, inject_crate: bool) -> Collector {
|
||||
use_headers: bool, opts: TestOptions) -> Collector {
|
||||
Collector {
|
||||
tests: Vec::new(),
|
||||
names: Vec::new(),
|
||||
@ -340,7 +347,7 @@ impl Collector {
|
||||
use_headers: use_headers,
|
||||
current_header: None,
|
||||
cratename: cratename,
|
||||
inject_crate: inject_crate
|
||||
opts: opts,
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,13 +364,14 @@ impl Collector {
|
||||
let libs = self.libs.clone();
|
||||
let externs = self.externs.clone();
|
||||
let cratename = self.cratename.to_string();
|
||||
let inject_crate = self.inject_crate;
|
||||
let opts = self.opts.clone();
|
||||
debug!("Creating test {}: {}", name, test);
|
||||
self.tests.push(testing::TestDescAndFn {
|
||||
desc: testing::TestDesc {
|
||||
name: testing::DynTestName(name),
|
||||
ignore: should_ignore,
|
||||
should_panic: testing::ShouldPanic::No, // compiler failures are test failures
|
||||
// compiler failures are test failures
|
||||
should_panic: testing::ShouldPanic::No,
|
||||
},
|
||||
testfn: testing::DynTestFn(Box::new(move|| {
|
||||
runtest(&test,
|
||||
@ -373,7 +381,7 @@ impl Collector {
|
||||
should_panic,
|
||||
no_run,
|
||||
as_test_harness,
|
||||
inject_crate);
|
||||
&opts);
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
//! usable for clean
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::mem;
|
||||
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
@ -40,6 +41,7 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> {
|
||||
pub cx: &'a core::DocContext<'tcx>,
|
||||
pub analysis: Option<&'a core::CrateAnalysis>,
|
||||
view_item_stack: HashSet<ast::NodeId>,
|
||||
inlining_from_glob: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
@ -54,6 +56,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
cx: cx,
|
||||
analysis: analysis,
|
||||
view_item_stack: stack,
|
||||
inlining_from_glob: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +123,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
|
||||
pub fn visit_fn(&mut self, item: &ast::Item,
|
||||
name: ast::Ident, fd: &ast::FnDecl,
|
||||
unsafety: &ast::Unsafety, _abi: &abi::Abi,
|
||||
unsafety: &ast::Unsafety, abi: &abi::Abi,
|
||||
gen: &ast::Generics) -> Function {
|
||||
debug!("Visiting fn");
|
||||
Function {
|
||||
@ -133,6 +136,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
whence: item.span,
|
||||
generics: gen.clone(),
|
||||
unsafety: *unsafety,
|
||||
abi: *abi,
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,6 +213,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
let ret = match tcx.map.get(def.node) {
|
||||
ast_map::NodeItem(it) => {
|
||||
if glob {
|
||||
let prev = mem::replace(&mut self.inlining_from_glob, true);
|
||||
match it.node {
|
||||
ast::ItemMod(ref m) => {
|
||||
for i in &m.items {
|
||||
@ -218,6 +223,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
ast::ItemEnum(..) => {}
|
||||
_ => { panic!("glob not mapped to a module or enum"); }
|
||||
}
|
||||
self.inlining_from_glob = prev;
|
||||
} else {
|
||||
self.visit_item(it, renamed, om);
|
||||
}
|
||||
@ -356,7 +362,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
vis: item.vis,
|
||||
stab: self.stability(item.id),
|
||||
};
|
||||
om.impls.push(i);
|
||||
// Don't duplicate impls when inlining glob imports, we'll pick
|
||||
// them up regardless of where they're located.
|
||||
if !self.inlining_from_glob {
|
||||
om.impls.push(i);
|
||||
}
|
||||
},
|
||||
ast::ItemDefaultImpl(unsafety, ref trait_ref) => {
|
||||
let i = DefaultImpl {
|
||||
@ -366,7 +376,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
attrs: item.attrs.clone(),
|
||||
whence: item.span,
|
||||
};
|
||||
om.def_traits.push(i);
|
||||
// see comment above about ItemImpl
|
||||
if !self.inlining_from_glob {
|
||||
om.def_traits.push(i);
|
||||
}
|
||||
}
|
||||
ast::ItemForeignMod(ref fm) => {
|
||||
om.foreigns.push(fm.clone());
|
||||
|
@ -304,7 +304,6 @@ impl<T, S> HashSet<T, S>
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::collections::HashSet;
|
||||
/// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
|
||||
/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
|
||||
@ -335,7 +334,6 @@ impl<T, S> HashSet<T, S>
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::collections::HashSet;
|
||||
/// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
|
||||
/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
|
||||
@ -362,7 +360,6 @@ impl<T, S> HashSet<T, S>
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::collections::HashSet;
|
||||
/// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
|
||||
/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
|
||||
@ -388,7 +385,6 @@ impl<T, S> HashSet<T, S>
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::collections::HashSet;
|
||||
/// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
|
||||
/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
|
||||
@ -471,7 +467,6 @@ impl<T, S> HashSet<T, S>
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::collections::HashSet;
|
||||
///
|
||||
/// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
|
||||
@ -491,7 +486,6 @@ impl<T, S> HashSet<T, S>
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::collections::HashSet;
|
||||
///
|
||||
/// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
|
||||
@ -513,7 +507,6 @@ impl<T, S> HashSet<T, S>
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::collections::HashSet;
|
||||
///
|
||||
/// let sup: HashSet<_> = [1, 2, 3].iter().cloned().collect();
|
||||
@ -535,7 +528,6 @@ impl<T, S> HashSet<T, S>
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::collections::HashSet;
|
||||
///
|
||||
/// let sub: HashSet<_> = [1, 2].iter().cloned().collect();
|
||||
|
@ -10,16 +10,18 @@
|
||||
|
||||
//! Collection types.
|
||||
//!
|
||||
//! Rust's standard collection library provides efficient implementations of the most common
|
||||
//! general purpose programming data structures. By using the standard implementations,
|
||||
//! it should be possible for two libraries to communicate without significant data conversion.
|
||||
//! Rust's standard collection library provides efficient implementations of the
|
||||
//! most common general purpose programming data structures. By using the
|
||||
//! standard implementations, it should be possible for two libraries to
|
||||
//! communicate without significant data conversion.
|
||||
//!
|
||||
//! To get this out of the way: you should probably just use `Vec` or `HashMap`. These two
|
||||
//! collections cover most use cases for generic data storage and processing. They are
|
||||
//! exceptionally good at doing what they do. All the other collections in the standard
|
||||
//! library have specific use cases where they are the optimal choice, but these cases are
|
||||
//! borderline *niche* in comparison. Even when `Vec` and `HashMap` are technically suboptimal,
|
||||
//! they're probably a good enough choice to get started.
|
||||
//! To get this out of the way: you should probably just use `Vec` or `HashMap`.
|
||||
//! These two collections cover most use cases for generic data storage and
|
||||
//! processing. They are exceptionally good at doing what they do. All the other
|
||||
//! collections in the standard library have specific use cases where they are
|
||||
//! the optimal choice, but these cases are borderline *niche* in comparison.
|
||||
//! Even when `Vec` and `HashMap` are technically suboptimal, they're probably a
|
||||
//! good enough choice to get started.
|
||||
//!
|
||||
//! Rust's collections can be grouped into four major categories:
|
||||
//!
|
||||
@ -30,28 +32,31 @@
|
||||
//!
|
||||
//! # When Should You Use Which Collection?
|
||||
//!
|
||||
//! These are fairly high-level and quick break-downs of when each collection should be
|
||||
//! considered. Detailed discussions of strengths and weaknesses of individual collections
|
||||
//! can be found on their own documentation pages.
|
||||
//! These are fairly high-level and quick break-downs of when each collection
|
||||
//! should be considered. Detailed discussions of strengths and weaknesses of
|
||||
//! individual collections can be found on their own documentation pages.
|
||||
//!
|
||||
//! ### Use a `Vec` when:
|
||||
//! * You want to collect items up to be processed or sent elsewhere later, and don't care about
|
||||
//! any properties of the actual values being stored.
|
||||
//! * You want a sequence of elements in a particular order, and will only be appending to
|
||||
//! (or near) the end.
|
||||
//! * You want to collect items up to be processed or sent elsewhere later, and
|
||||
//! don't care about any properties of the actual values being stored.
|
||||
//! * You want a sequence of elements in a particular order, and will only be
|
||||
//! appending to (or near) the end.
|
||||
//! * You want a stack.
|
||||
//! * You want a resizable array.
|
||||
//! * You want a heap-allocated array.
|
||||
//!
|
||||
//! ### Use a `VecDeque` when:
|
||||
//! * You want a `Vec` that supports efficient insertion at both ends of the sequence.
|
||||
//! * You want a `Vec` that supports efficient insertion at both ends of the
|
||||
//! sequence.
|
||||
//! * You want a queue.
|
||||
//! * You want a double-ended queue (deque).
|
||||
//!
|
||||
//! ### Use a `LinkedList` when:
|
||||
//! * You want a `Vec` or `VecDeque` of unknown size, and can't tolerate amortization.
|
||||
//! * You want a `Vec` or `VecDeque` of unknown size, and can't tolerate
|
||||
//! amortization.
|
||||
//! * You want to efficiently split and append lists.
|
||||
//! * You are *absolutely* certain you *really*, *truly*, want a doubly linked list.
|
||||
//! * You are *absolutely* certain you *really*, *truly*, want a doubly linked
|
||||
//! list.
|
||||
//!
|
||||
//! ### Use a `HashMap` when:
|
||||
//! * You want to associate arbitrary keys with an arbitrary value.
|
||||
@ -60,7 +65,8 @@
|
||||
//!
|
||||
//! ### Use a `BTreeMap` when:
|
||||
//! * You're interested in what the smallest or largest key-value pair is.
|
||||
//! * You want to find the largest or smallest key that is smaller or larger than something
|
||||
//! * You want to find the largest or smallest key that is smaller or larger
|
||||
//! than something
|
||||
//! * You want to be able to get all of the entries in order on-demand.
|
||||
//! * You want a sorted map.
|
||||
//!
|
||||
@ -81,29 +87,34 @@
|
||||
//! * You want a `BitVec`, but want `Set` properties
|
||||
//!
|
||||
//! ### Use a `BinaryHeap` when:
|
||||
//! * You want to store a bunch of elements, but only ever want to process the "biggest"
|
||||
//! or "most important" one at any given time.
|
||||
//!
|
||||
//! * You want to store a bunch of elements, but only ever want to process the
|
||||
//! "biggest" or "most important" one at any given time.
|
||||
//! * You want a priority queue.
|
||||
//!
|
||||
//! # Performance
|
||||
//!
|
||||
//! Choosing the right collection for the job requires an understanding of what each collection
|
||||
//! is good at. Here we briefly summarize the performance of different collections for certain
|
||||
//! important operations. For further details, see each type's documentation, and note that the
|
||||
//! names of actual methods may differ from the tables below on certain collections.
|
||||
//! Choosing the right collection for the job requires an understanding of what
|
||||
//! each collection is good at. Here we briefly summarize the performance of
|
||||
//! different collections for certain important operations. For further details,
|
||||
//! see each type's documentation, and note that the names of actual methods may
|
||||
//! differ from the tables below on certain collections.
|
||||
//!
|
||||
//! Throughout the documentation, we will follow a few conventions. For all operations,
|
||||
//! the collection's size is denoted by n. If another collection is involved in the operation, it
|
||||
//! contains m elements. Operations which have an *amortized* cost are suffixed with a `*`.
|
||||
//! Operations with an *expected* cost are suffixed with a `~`.
|
||||
//! Throughout the documentation, we will follow a few conventions. For all
|
||||
//! operations, the collection's size is denoted by n. If another collection is
|
||||
//! involved in the operation, it contains m elements. Operations which have an
|
||||
//! *amortized* cost are suffixed with a `*`. Operations with an *expected*
|
||||
//! cost are suffixed with a `~`.
|
||||
//!
|
||||
//! All amortized costs are for the potential need to resize when capacity is exhausted.
|
||||
//! If a resize occurs it will take O(n) time. Our collections never automatically shrink,
|
||||
//! so removal operations aren't amortized. Over a sufficiently large series of
|
||||
//! operations, the average cost per operation will deterministically equal the given cost.
|
||||
//! All amortized costs are for the potential need to resize when capacity is
|
||||
//! exhausted. If a resize occurs it will take O(n) time. Our collections never
|
||||
//! automatically shrink, so removal operations aren't amortized. Over a
|
||||
//! sufficiently large series of operations, the average cost per operation will
|
||||
//! deterministically equal the given cost.
|
||||
//!
|
||||
//! Only HashMap has expected costs, due to the probabilistic nature of hashing. It is
|
||||
//! theoretically possible, though very unlikely, for HashMap to experience worse performance.
|
||||
//! Only HashMap has expected costs, due to the probabilistic nature of hashing.
|
||||
//! It is theoretically possible, though very unlikely, for HashMap to
|
||||
//! experience worse performance.
|
||||
//!
|
||||
//! ## Sequences
|
||||
//!
|
||||
@ -120,7 +131,8 @@
|
||||
//!
|
||||
//! ## Maps
|
||||
//!
|
||||
//! For Sets, all operations have the cost of the equivalent Map operation. For BitSet,
|
||||
//! For Sets, all operations have the cost of the equivalent Map operation. For
|
||||
//! BitSet,
|
||||
//! refer to VecMap.
|
||||
//!
|
||||
//! | | get | insert | remove | predecessor |
|
||||
@ -129,85 +141,95 @@
|
||||
//! | BTreeMap | O(log n) | O(log n) | O(log n) | O(log n) |
|
||||
//! | VecMap | O(1) | O(1)? | O(1) | O(n) |
|
||||
//!
|
||||
//! Note that VecMap is *incredibly* inefficient in terms of space. The O(1) insertion time
|
||||
//! assumes space for the element is already allocated. Otherwise, a large key may require a
|
||||
//! massive reallocation, with no direct relation to the number of elements in the collection.
|
||||
//! VecMap should only be seriously considered for small keys.
|
||||
//! Note that VecMap is *incredibly* inefficient in terms of space. The O(1)
|
||||
//! insertion time assumes space for the element is already allocated.
|
||||
//! Otherwise, a large key may require a massive reallocation, with no direct
|
||||
//! relation to the number of elements in the collection. VecMap should only be
|
||||
//! seriously considered for small keys.
|
||||
//!
|
||||
//! Note also that BTreeMap's precise preformance depends on the value of B.
|
||||
//!
|
||||
//! # Correct and Efficient Usage of Collections
|
||||
//!
|
||||
//! Of course, knowing which collection is the right one for the job doesn't instantly
|
||||
//! permit you to use it correctly. Here are some quick tips for efficient and correct
|
||||
//! usage of the standard collections in general. If you're interested in how to use a
|
||||
//! specific collection in particular, consult its documentation for detailed discussion
|
||||
//! and code examples.
|
||||
//! Of course, knowing which collection is the right one for the job doesn't
|
||||
//! instantly permit you to use it correctly. Here are some quick tips for
|
||||
//! efficient and correct usage of the standard collections in general. If
|
||||
//! you're interested in how to use a specific collection in particular, consult
|
||||
//! its documentation for detailed discussion and code examples.
|
||||
//!
|
||||
//! ## Capacity Management
|
||||
//!
|
||||
//! Many collections provide several constructors and methods that refer to "capacity".
|
||||
//! These collections are generally built on top of an array. Optimally, this array would be
|
||||
//! exactly the right size to fit only the elements stored in the collection, but for the
|
||||
//! collection to do this would be very inefficient. If the backing array was exactly the
|
||||
//! right size at all times, then every time an element is inserted, the collection would
|
||||
//! have to grow the array to fit it. Due to the way memory is allocated and managed on most
|
||||
//! computers, this would almost surely require allocating an entirely new array and
|
||||
//! copying every single element from the old one into the new one. Hopefully you can
|
||||
//! see that this wouldn't be very efficient to do on every operation.
|
||||
//! Many collections provide several constructors and methods that refer to
|
||||
//! "capacity". These collections are generally built on top of an array.
|
||||
//! Optimally, this array would be exactly the right size to fit only the
|
||||
//! elements stored in the collection, but for the collection to do this would
|
||||
//! be very inefficient. If the backing array was exactly the right size at all
|
||||
//! times, then every time an element is inserted, the collection would have to
|
||||
//! grow the array to fit it. Due to the way memory is allocated and managed on
|
||||
//! most computers, this would almost surely require allocating an entirely new
|
||||
//! array and copying every single element from the old one into the new one.
|
||||
//! Hopefully you can see that this wouldn't be very efficient to do on every
|
||||
//! operation.
|
||||
//!
|
||||
//! Most collections therefore use an *amortized* allocation strategy. They generally let
|
||||
//! themselves have a fair amount of unoccupied space so that they only have to grow
|
||||
//! on occasion. When they do grow, they allocate a substantially larger array to move
|
||||
//! the elements into so that it will take a while for another grow to be required. While
|
||||
//! this strategy is great in general, it would be even better if the collection *never*
|
||||
//! had to resize its backing array. Unfortunately, the collection itself doesn't have
|
||||
//! enough information to do this itself. Therefore, it is up to us programmers to give it
|
||||
//! hints.
|
||||
//! Most collections therefore use an *amortized* allocation strategy. They
|
||||
//! generally let themselves have a fair amount of unoccupied space so that they
|
||||
//! only have to grow on occasion. When they do grow, they allocate a
|
||||
//! substantially larger array to move the elements into so that it will take a
|
||||
//! while for another grow to be required. While this strategy is great in
|
||||
//! general, it would be even better if the collection *never* had to resize its
|
||||
//! backing array. Unfortunately, the collection itself doesn't have enough
|
||||
//! information to do this itself. Therefore, it is up to us programmers to give
|
||||
//! it hints.
|
||||
//!
|
||||
//! Any `with_capacity` constructor will instruct the collection to allocate enough space
|
||||
//! for the specified number of elements. Ideally this will be for exactly that many
|
||||
//! elements, but some implementation details may prevent this. `Vec` and `VecDeque` can
|
||||
//! be relied on to allocate exactly the requested amount, though. Use `with_capacity`
|
||||
//! when you know exactly how many elements will be inserted, or at least have a
|
||||
//! reasonable upper-bound on that number.
|
||||
//! Any `with_capacity` constructor will instruct the collection to allocate
|
||||
//! enough space for the specified number of elements. Ideally this will be for
|
||||
//! exactly that many elements, but some implementation details may prevent
|
||||
//! this. `Vec` and `VecDeque` can be relied on to allocate exactly the
|
||||
//! requested amount, though. Use `with_capacity` when you know exactly how many
|
||||
//! elements will be inserted, or at least have a reasonable upper-bound on that
|
||||
//! number.
|
||||
//!
|
||||
//! When anticipating a large influx of elements, the `reserve` family of methods can
|
||||
//! be used to hint to the collection how much room it should make for the coming items.
|
||||
//! As with `with_capacity`, the precise behavior of these methods will be specific to
|
||||
//! the collection of interest.
|
||||
//! When anticipating a large influx of elements, the `reserve` family of
|
||||
//! methods can be used to hint to the collection how much room it should make
|
||||
//! for the coming items. As with `with_capacity`, the precise behavior of
|
||||
//! these methods will be specific to the collection of interest.
|
||||
//!
|
||||
//! For optimal performance, collections will generally avoid shrinking themselves.
|
||||
//! If you believe that a collection will not soon contain any more elements, or
|
||||
//! just really need the memory, the `shrink_to_fit` method prompts the collection
|
||||
//! to shrink the backing array to the minimum size capable of holding its elements.
|
||||
//! For optimal performance, collections will generally avoid shrinking
|
||||
//! themselves. If you believe that a collection will not soon contain any more
|
||||
//! elements, or just really need the memory, the `shrink_to_fit` method prompts
|
||||
//! the collection to shrink the backing array to the minimum size capable of
|
||||
//! holding its elements.
|
||||
//!
|
||||
//! Finally, if ever you're interested in what the actual capacity of the collection is,
|
||||
//! most collections provide a `capacity` method to query this information on demand.
|
||||
//! This can be useful for debugging purposes, or for use with the `reserve` methods.
|
||||
//! Finally, if ever you're interested in what the actual capacity of the
|
||||
//! collection is, most collections provide a `capacity` method to query this
|
||||
//! information on demand. This can be useful for debugging purposes, or for
|
||||
//! use with the `reserve` methods.
|
||||
//!
|
||||
//! ## Iterators
|
||||
//!
|
||||
//! Iterators are a powerful and robust mechanism used throughout Rust's standard
|
||||
//! libraries. Iterators provide a sequence of values in a generic, safe, efficient
|
||||
//! and convenient way. The contents of an iterator are usually *lazily* evaluated,
|
||||
//! so that only the values that are actually needed are ever actually produced, and
|
||||
//! no allocation need be done to temporarily store them. Iterators are primarily
|
||||
//! consumed using a `for` loop, although many functions also take iterators where
|
||||
//! a collection or sequence of values is desired.
|
||||
//! Iterators are a powerful and robust mechanism used throughout Rust's
|
||||
//! standard libraries. Iterators provide a sequence of values in a generic,
|
||||
//! safe, efficient and convenient way. The contents of an iterator are usually
|
||||
//! *lazily* evaluated, so that only the values that are actually needed are
|
||||
//! ever actually produced, and no allocation need be done to temporarily store
|
||||
//! them. Iterators are primarily consumed using a `for` loop, although many
|
||||
//! functions also take iterators where a collection or sequence of values is
|
||||
//! desired.
|
||||
//!
|
||||
//! All of the standard collections provide several iterators for performing bulk
|
||||
//! manipulation of their contents. The three primary iterators almost every collection
|
||||
//! should provide are `iter`, `iter_mut`, and `into_iter`. Some of these are not
|
||||
//! provided on collections where it would be unsound or unreasonable to provide them.
|
||||
//! All of the standard collections provide several iterators for performing
|
||||
//! bulk manipulation of their contents. The three primary iterators almost
|
||||
//! every collection should provide are `iter`, `iter_mut`, and `into_iter`.
|
||||
//! Some of these are not provided on collections where it would be unsound or
|
||||
//! unreasonable to provide them.
|
||||
//!
|
||||
//! `iter` provides an iterator of immutable references to all the contents of a
|
||||
//! collection in the most "natural" order. For sequence collections like `Vec`, this
|
||||
//! means the items will be yielded in increasing order of index starting at 0. For ordered
|
||||
//! collections like `BTreeMap`, this means that the items will be yielded in sorted order.
|
||||
//! For unordered collections like `HashMap`, the items will be yielded in whatever order
|
||||
//! the internal representation made most convenient. This is great for reading through
|
||||
//! all the contents of the collection.
|
||||
//! collection in the most "natural" order. For sequence collections like `Vec`,
|
||||
//! this means the items will be yielded in increasing order of index starting
|
||||
//! at 0. For ordered collections like `BTreeMap`, this means that the items
|
||||
//! will be yielded in sorted order. For unordered collections like `HashMap`,
|
||||
//! the items will be yielded in whatever order the internal representation made
|
||||
//! most convenient. This is great for reading through all the contents of the
|
||||
//! collection.
|
||||
//!
|
||||
//! ```
|
||||
//! let vec = vec![1, 2, 3, 4];
|
||||
@ -216,8 +238,8 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! `iter_mut` provides an iterator of *mutable* references in the same order as `iter`.
|
||||
//! This is great for mutating all the contents of the collection.
|
||||
//! `iter_mut` provides an iterator of *mutable* references in the same order as
|
||||
//! `iter`. This is great for mutating all the contents of the collection.
|
||||
//!
|
||||
//! ```
|
||||
//! let mut vec = vec![1, 2, 3, 4];
|
||||
@ -226,13 +248,14 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! `into_iter` transforms the actual collection into an iterator over its contents
|
||||
//! by-value. This is great when the collection itself is no longer needed, and the
|
||||
//! values are needed elsewhere. Using `extend` with `into_iter` is the main way that
|
||||
//! contents of one collection are moved into another. Calling `collect` on an iterator
|
||||
//! itself is also a great way to convert one collection into another. Both of these
|
||||
//! methods should internally use the capacity management tools discussed in the
|
||||
//! previous section to do this as efficiently as possible.
|
||||
//! `into_iter` transforms the actual collection into an iterator over its
|
||||
//! contents by-value. This is great when the collection itself is no longer
|
||||
//! needed, and the values are needed elsewhere. Using `extend` with `into_iter`
|
||||
//! is the main way that contents of one collection are moved into another.
|
||||
//! Calling `collect` on an iterator itself is also a great way to convert one
|
||||
//! collection into another. Both of these methods should internally use the
|
||||
//! capacity management tools discussed in the previous section to do this as
|
||||
//! efficiently as possible.
|
||||
//!
|
||||
//! ```
|
||||
//! let mut vec1 = vec![1, 2, 3, 4];
|
||||
@ -247,11 +270,12 @@
|
||||
//! let buf: VecDeque<_> = vec.into_iter().collect();
|
||||
//! ```
|
||||
//!
|
||||
//! Iterators also provide a series of *adapter* methods for performing common tasks to
|
||||
//! sequences. Among the adapters are functional favorites like `map`, `fold`, `skip`,
|
||||
//! and `take`. Of particular interest to collections is the `rev` adapter, that
|
||||
//! reverses any iterator that supports this operation. Most collections provide reversible
|
||||
//! iterators as the way to iterate over them in reverse order.
|
||||
//! Iterators also provide a series of *adapter* methods for performing common
|
||||
//! tasks to sequences. Among the adapters are functional favorites like `map`,
|
||||
//! `fold`, `skip`, and `take`. Of particular interest to collections is the
|
||||
//! `rev` adapter, that reverses any iterator that supports this operation. Most
|
||||
//! collections provide reversible iterators as the way to iterate over them in
|
||||
//! reverse order.
|
||||
//!
|
||||
//! ```
|
||||
//! let vec = vec![1, 2, 3, 4];
|
||||
@ -260,48 +284,50 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Several other collection methods also return iterators to yield a sequence of results
|
||||
//! but avoid allocating an entire collection to store the result in. This provides maximum
|
||||
//! flexibility as `collect` or `extend` can be called to "pipe" the sequence into any
|
||||
//! collection if desired. Otherwise, the sequence can be looped over with a `for` loop. The
|
||||
//! iterator can also be discarded after partial use, preventing the computation of the unused
|
||||
//! items.
|
||||
//! Several other collection methods also return iterators to yield a sequence
|
||||
//! of results but avoid allocating an entire collection to store the result in.
|
||||
//! This provides maximum flexibility as `collect` or `extend` can be called to
|
||||
//! "pipe" the sequence into any collection if desired. Otherwise, the sequence
|
||||
//! can be looped over with a `for` loop. The iterator can also be discarded
|
||||
//! after partial use, preventing the computation of the unused items.
|
||||
//!
|
||||
//! ## Entries
|
||||
//!
|
||||
//! The `entry` API is intended to provide an efficient mechanism for manipulating
|
||||
//! the contents of a map conditionally on the presence of a key or not. The primary
|
||||
//! motivating use case for this is to provide efficient accumulator maps. For instance,
|
||||
//! if one wishes to maintain a count of the number of times each key has been seen,
|
||||
//! they will have to perform some conditional logic on whether this is the first time
|
||||
//! the key has been seen or not. Normally, this would require a `find` followed by an
|
||||
//! `insert`, effectively duplicating the search effort on each insertion.
|
||||
//! The `entry` API is intended to provide an efficient mechanism for
|
||||
//! manipulating the contents of a map conditionally on the presence of a key or
|
||||
//! not. The primary motivating use case for this is to provide efficient
|
||||
//! accumulator maps. For instance, if one wishes to maintain a count of the
|
||||
//! number of times each key has been seen, they will have to perform some
|
||||
//! conditional logic on whether this is the first time the key has been seen or
|
||||
//! not. Normally, this would require a `find` followed by an `insert`,
|
||||
//! effectively duplicating the search effort on each insertion.
|
||||
//!
|
||||
//! When a user calls `map.entry(&key)`, the map will search for the key and then yield
|
||||
//! a variant of the `Entry` enum.
|
||||
//! When a user calls `map.entry(&key)`, the map will search for the key and
|
||||
//! then yield a variant of the `Entry` enum.
|
||||
//!
|
||||
//! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case the
|
||||
//! only valid operation is to `insert` a value into the entry. When this is done,
|
||||
//! the vacant entry is consumed and converted into a mutable reference to the
|
||||
//! the value that was inserted. This allows for further manipulation of the value
|
||||
//! beyond the lifetime of the search itself. This is useful if complex logic needs to
|
||||
//! be performed on the value regardless of whether the value was just inserted.
|
||||
//! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case
|
||||
//! the only valid operation is to `insert` a value into the entry. When this is
|
||||
//! done, the vacant entry is consumed and converted into a mutable reference to
|
||||
//! the the value that was inserted. This allows for further manipulation of the
|
||||
//! value beyond the lifetime of the search itself. This is useful if complex
|
||||
//! logic needs to be performed on the value regardless of whether the value was
|
||||
//! just inserted.
|
||||
//!
|
||||
//! If an `Occupied(entry)` is yielded, then the key *was* found. In this case, the user
|
||||
//! has several options: they can `get`, `insert`, or `remove` the value of the occupied
|
||||
//! entry. Additionally, they can convert the occupied entry into a mutable reference
|
||||
//! to its value, providing symmetry to the vacant `insert` case.
|
||||
//! If an `Occupied(entry)` is yielded, then the key *was* found. In this case,
|
||||
//! the user has several options: they can `get`, `insert`, or `remove` the
|
||||
//! value of the occupied entry. Additionally, they can convert the occupied
|
||||
//! entry into a mutable reference to its value, providing symmetry to the
|
||||
//! vacant `insert` case.
|
||||
//!
|
||||
//! ### Examples
|
||||
//!
|
||||
//! Here are the two primary ways in which `entry` is used. First, a simple example
|
||||
//! where the logic performed on the values is trivial.
|
||||
//! Here are the two primary ways in which `entry` is used. First, a simple
|
||||
//! example where the logic performed on the values is trivial.
|
||||
//!
|
||||
//! #### Counting the number of times each character in a string occurs
|
||||
//!
|
||||
//! ```
|
||||
//! # #![feature(collections)]
|
||||
//! use std::collections::btree_map::{BTreeMap, Entry};
|
||||
//! use std::collections::btree_map::BTreeMap;
|
||||
//!
|
||||
//! let mut count = BTreeMap::new();
|
||||
//! let message = "she sells sea shells by the sea shore";
|
||||
@ -318,15 +344,14 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! When the logic to be performed on the value is more complex, we may simply use
|
||||
//! the `entry` API to ensure that the value is initialized, and perform the logic
|
||||
//! afterwards.
|
||||
//! When the logic to be performed on the value is more complex, we may simply
|
||||
//! use the `entry` API to ensure that the value is initialized, and perform the
|
||||
//! logic afterwards.
|
||||
//!
|
||||
//! #### Tracking the inebriation of customers at a bar
|
||||
//!
|
||||
//! ```
|
||||
//! # #![feature(collections)]
|
||||
//! use std::collections::btree_map::{BTreeMap, Entry};
|
||||
//! use std::collections::btree_map::BTreeMap;
|
||||
//!
|
||||
//! // A client of the bar. They have an id and a blood alcohol level.
|
||||
//! struct Person { id: u32, blood_alcohol: f32 }
|
||||
|
@ -96,14 +96,16 @@ pub struct WalkDir {
|
||||
|
||||
/// Options and flags which can be used to configure how a file is opened.
|
||||
///
|
||||
/// This builder exposes the ability to configure how a `File` is opened and what operations are
|
||||
/// permitted on the open file. The `File::open` and `File::create` methods are aliases for
|
||||
/// commonly used options using this builder.
|
||||
/// This builder exposes the ability to configure how a `File` is opened and
|
||||
/// what operations are permitted on the open file. The `File::open` and
|
||||
/// `File::create` methods are aliases for commonly used options using this
|
||||
/// builder.
|
||||
///
|
||||
/// Generally speaking, when using `OpenOptions`, you'll first call `new()`, then chain calls to
|
||||
/// methods to set each option, then call `open()`, passing the path of the file you're trying to
|
||||
/// open. This will give you a [`io::Result`][result] with a [`File`][file] inside that you can
|
||||
/// further operate on.
|
||||
/// Generally speaking, when using `OpenOptions`, you'll first call `new()`,
|
||||
/// then chain calls to methods to set each option, then call `open()`, passing
|
||||
/// the path of the file you're trying to open. This will give you a
|
||||
/// [`io::Result`][result] with a [`File`][file] inside that you can further
|
||||
/// operate on.
|
||||
///
|
||||
/// [result]: ../io/type.Result.html
|
||||
/// [file]: struct.File.html
|
||||
@ -113,16 +115,15 @@ pub struct WalkDir {
|
||||
/// Opening a file to read:
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs;
|
||||
/// use std::fs::OpenOptions;
|
||||
///
|
||||
/// let file = OpenOptions::new().read(true).open("foo.txt");
|
||||
/// ```
|
||||
///
|
||||
/// Opening a file for both reading and writing, as well as creating it if it doesn't exist:
|
||||
/// Opening a file for both reading and writing, as well as creating it if it
|
||||
/// doesn't exist:
|
||||
///
|
||||
/// ```
|
||||
/// use std::fs;
|
||||
/// use std::fs::OpenOptions;
|
||||
///
|
||||
/// let file = OpenOptions::new()
|
||||
@ -771,7 +772,9 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
|
||||
/// ```no_run
|
||||
/// use std::fs;
|
||||
///
|
||||
/// fs::copy("foo.txt", "bar.txt");
|
||||
/// # fn foo() -> std::io::Result<()> {
|
||||
/// try!(fs::copy("foo.txt", "bar.txt"));
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
|
||||
|
@ -14,6 +14,7 @@
|
||||
//! by adding a glob import to the top of I/O heavy modules:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_imports)]
|
||||
//! use std::io::prelude::*;
|
||||
//! ```
|
||||
//!
|
||||
|
@ -103,7 +103,8 @@
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/nightly/",
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
#![doc(test(no_crate_inject))]
|
||||
#![doc(test(no_crate_inject, attr(deny(warnings))))]
|
||||
#![doc(test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
|
||||
|
||||
#![feature(alloc)]
|
||||
#![feature(box_syntax)]
|
||||
|
@ -281,7 +281,6 @@ impl hash::Hash for SocketAddrV6 {
|
||||
/// Some examples:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![feature(net)]
|
||||
/// use std::net::{SocketAddrV4, TcpStream, UdpSocket, TcpListener, Ipv4Addr};
|
||||
///
|
||||
/// fn main() {
|
||||
@ -302,7 +301,7 @@ impl hash::Hash for SocketAddrV6 {
|
||||
/// let tcp_l = TcpListener::bind("localhost:12345");
|
||||
///
|
||||
/// let mut udp_s = UdpSocket::bind(("127.0.0.1", port)).unwrap();
|
||||
/// udp_s.send_to(&[7], (ip, 23451));
|
||||
/// udp_s.send_to(&[7], (ip, 23451)).unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -27,7 +27,6 @@ use sys_common::{AsInner, FromInner};
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![feature(net)]
|
||||
/// use std::io::prelude::*;
|
||||
/// use std::net::TcpStream;
|
||||
///
|
||||
@ -47,7 +46,6 @@ pub struct TcpStream(net_imp::TcpStream);
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![feature(net)]
|
||||
/// use std::net::{TcpListener, TcpStream};
|
||||
/// use std::thread;
|
||||
///
|
||||
|
@ -27,7 +27,6 @@ use sys_common::{AsInner, FromInner};
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![feature(net)]
|
||||
/// use std::net::UdpSocket;
|
||||
///
|
||||
/// # fn foo() -> std::io::Result<()> {
|
||||
|
@ -422,7 +422,6 @@ impl f32 {
|
||||
/// [subnormal][subnormal], or `NaN`.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(std_misc)]
|
||||
/// use std::f32;
|
||||
///
|
||||
/// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32
|
||||
@ -856,7 +855,7 @@ impl f32 {
|
||||
/// Convert radians to degrees.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(std_misc, core)]
|
||||
/// # #![feature(std_misc)]
|
||||
/// use std::f32::{self, consts};
|
||||
///
|
||||
/// let angle = consts::PI;
|
||||
@ -987,7 +986,6 @@ impl f32 {
|
||||
/// * Else: `self - other`
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(std_misc)]
|
||||
/// use std::f32;
|
||||
///
|
||||
/// let x = 3.0f32;
|
||||
@ -1008,7 +1006,6 @@ impl f32 {
|
||||
/// Take the cubic root of a number.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(std_misc)]
|
||||
/// use std::f32;
|
||||
///
|
||||
/// let x = 8.0f32;
|
||||
@ -1210,8 +1207,6 @@ impl f32 {
|
||||
/// number is close to zero.
|
||||
///
|
||||
/// ```
|
||||
/// use std::f64;
|
||||
///
|
||||
/// let x = 7.0f64;
|
||||
///
|
||||
/// // e^(ln(7)) - 1
|
||||
|
@ -280,7 +280,6 @@ pub trait Float
|
||||
/// [subnormal][subnormal], or `NaN`.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(std_misc)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f32;
|
||||
///
|
||||
@ -307,7 +306,6 @@ pub trait Float
|
||||
/// predicate instead.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::{Float, FpCategory};
|
||||
/// use std::f32;
|
||||
///
|
||||
@ -417,7 +415,6 @@ pub trait Float
|
||||
/// number is `Float::nan()`.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(std_misc)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -441,7 +438,6 @@ pub trait Float
|
||||
/// - `Float::nan()` if the number is `Float::nan()`
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(std_misc)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -686,7 +682,6 @@ pub trait Float
|
||||
/// Convert radians to degrees.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(std_misc, core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64::consts;
|
||||
///
|
||||
@ -701,7 +696,7 @@ pub trait Float
|
||||
/// Convert degrees to radians.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(std_misc, core)]
|
||||
/// # #![feature(std_misc)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64::consts;
|
||||
///
|
||||
@ -849,7 +844,6 @@ pub trait Float
|
||||
/// Computes the sine of a number (in radians).
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -864,7 +858,6 @@ pub trait Float
|
||||
/// Computes the cosine of a number (in radians).
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -879,7 +872,6 @@ pub trait Float
|
||||
/// Computes the tangent of a number (in radians).
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -895,7 +887,6 @@ pub trait Float
|
||||
/// [-1, 1].
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -913,7 +904,6 @@ pub trait Float
|
||||
/// [-1, 1].
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -949,7 +939,6 @@ pub trait Float
|
||||
/// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -975,7 +964,6 @@ pub trait Float
|
||||
/// `(sin(x), cos(x))`.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -1011,7 +999,6 @@ pub trait Float
|
||||
/// the operations were performed separately.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(std_misc, core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -1028,7 +1015,6 @@ pub trait Float
|
||||
/// Hyperbolic sine function.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -1047,7 +1033,6 @@ pub trait Float
|
||||
/// Hyperbolic cosine function.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -1066,7 +1051,6 @@ pub trait Float
|
||||
/// Hyperbolic tangent function.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
@ -1113,7 +1097,6 @@ pub trait Float
|
||||
/// Inverse hyperbolic tangent function.
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(core)]
|
||||
/// use std::num::Float;
|
||||
/// use std::f64;
|
||||
///
|
||||
|
@ -48,7 +48,7 @@
|
||||
//! * Read lines from stdin
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #![feature(old_io, old_path)]
|
||||
//! # #![feature(old_io)]
|
||||
//! use std::old_io as io;
|
||||
//! use std::old_io::*;
|
||||
//!
|
||||
|
@ -414,7 +414,7 @@ pub struct ParseError;
|
||||
/// Some examples:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # #![feature(old_io, core, convert)]
|
||||
/// # #![feature(old_io)]
|
||||
/// # #![allow(unused_must_use)]
|
||||
///
|
||||
/// use std::old_io::{TcpStream, TcpListener};
|
||||
|
@ -191,7 +191,7 @@ impl UnixListener {
|
||||
/// let server = Path::new("/path/to/my/socket");
|
||||
/// let stream = UnixListener::bind(&server);
|
||||
/// for mut client in stream.listen().incoming() {
|
||||
/// client.write(&[1, 2, 3, 4]);
|
||||
/// let _ = client.write(&[1, 2, 3, 4]);
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
|
@ -367,7 +367,7 @@ impl Command {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(old_io, core, convert)]
|
||||
/// # #![feature(old_io)]
|
||||
/// use std::old_io::Command;
|
||||
///
|
||||
/// let output = match Command::new("cat").arg("foot.txt").output() {
|
||||
|
@ -48,7 +48,7 @@
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```rust,ignore
|
||||
//! # #![feature(old_path, old_io)]
|
||||
//! use std::old_io::fs::PathExtensions;
|
||||
//! use std::old_path::{Path, GenericPath};
|
||||
@ -144,12 +144,10 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```no_run
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
/// # #[cfg(windows)] fn foo() {}
|
||||
/// # #[cfg(unix)] fn foo() {
|
||||
/// # fn main() {
|
||||
/// use std::old_path::Path;
|
||||
/// let path = Path::new("foo/bar");
|
||||
/// # }
|
||||
/// ```
|
||||
@ -170,12 +168,10 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```no_run
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
/// # #[cfg(windows)] fn foo() {}
|
||||
/// # #[cfg(unix)] fn foo() {
|
||||
/// # fn main() {
|
||||
/// use std::old_path::Path;
|
||||
/// let x: &[u8] = b"foo\0";
|
||||
/// assert!(Path::new_opt(x).is_none());
|
||||
/// # }
|
||||
@ -194,7 +190,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -213,7 +209,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -229,7 +225,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -246,7 +242,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -266,7 +262,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -285,7 +281,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -302,7 +298,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -323,7 +319,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -340,7 +336,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -361,7 +357,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -390,7 +386,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -412,7 +408,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -441,7 +437,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -461,7 +457,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -489,7 +485,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -541,7 +537,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -568,7 +564,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -594,7 +590,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -615,7 +611,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -632,7 +628,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -658,7 +654,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -689,7 +685,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -708,7 +704,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -735,7 +731,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -759,7 +755,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -778,7 +774,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -798,7 +794,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -819,7 +815,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
@ -837,7 +833,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// # #![feature(old_path)]
|
||||
/// use std::old_path::{Path, GenericPath};
|
||||
/// # foo();
|
||||
|
@ -38,8 +38,6 @@ use thread;
|
||||
/// # Examples
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # #![feature(process)]
|
||||
///
|
||||
/// use std::process::Command;
|
||||
///
|
||||
/// let output = Command::new("/bin/cat").arg("file.txt").output().unwrap_or_else(|e| {
|
||||
@ -267,10 +265,8 @@ impl Command {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(process)]
|
||||
/// use std::process::Command;
|
||||
///
|
||||
/// let output = Command::new("cat").arg("foot.txt").output().unwrap_or_else(|e| {
|
||||
/// let output = Command::new("cat").arg("foo.txt").output().unwrap_or_else(|e| {
|
||||
/// panic!("failed to execute process: {}", e)
|
||||
/// });
|
||||
///
|
||||
@ -291,7 +287,6 @@ impl Command {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(process)]
|
||||
/// use std::process::Command;
|
||||
///
|
||||
/// let status = Command::new("ls").status().unwrap_or_else(|e| {
|
||||
|
@ -95,7 +95,7 @@ macro_rules! thread_local {
|
||||
(static $name:ident: $t:ty = $init:expr) => (
|
||||
static $name: ::std::thread::LocalKey<$t> = {
|
||||
use std::cell::UnsafeCell as __UnsafeCell;
|
||||
use std::thread::__local::__impl::KeyInner as __KeyInner;
|
||||
use std::thread::__local::KeyInner as __KeyInner;
|
||||
use std::option::Option as __Option;
|
||||
use std::option::Option::None as __None;
|
||||
|
||||
@ -112,7 +112,7 @@ macro_rules! thread_local {
|
||||
(pub static $name:ident: $t:ty = $init:expr) => (
|
||||
pub static $name: ::std::thread::LocalKey<$t> = {
|
||||
use std::cell::UnsafeCell as __UnsafeCell;
|
||||
use std::thread::__local::__impl::KeyInner as __KeyInner;
|
||||
use std::thread::__local::KeyInner as __KeyInner;
|
||||
use std::option::Option as __Option;
|
||||
use std::option::Option::None as __None;
|
||||
|
||||
@ -156,20 +156,20 @@ macro_rules! __thread_local_inner {
|
||||
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
|
||||
not(target_arch = "aarch64")),
|
||||
thread_local)]
|
||||
static $name: ::std::thread::__local::__impl::KeyInner<$t> =
|
||||
static $name: ::std::thread::__local::KeyInner<$t> =
|
||||
__thread_local_inner!($init, $t);
|
||||
);
|
||||
(pub static $name:ident: $t:ty = $init:expr) => (
|
||||
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
|
||||
not(target_arch = "aarch64")),
|
||||
thread_local)]
|
||||
pub static $name: ::std::thread::__local::__impl::KeyInner<$t> =
|
||||
pub static $name: ::std::thread::__local::KeyInner<$t> =
|
||||
__thread_local_inner!($init, $t);
|
||||
);
|
||||
($init:expr, $t:ty) => ({
|
||||
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
|
||||
const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
|
||||
::std::thread::__local::__impl::KeyInner {
|
||||
const _INIT: ::std::thread::__local::KeyInner<$t> = {
|
||||
::std::thread::__local::KeyInner {
|
||||
inner: ::std::cell::UnsafeCell { value: $init },
|
||||
dtor_registered: ::std::cell::UnsafeCell { value: false },
|
||||
dtor_running: ::std::cell::UnsafeCell { value: false },
|
||||
@ -178,13 +178,13 @@ macro_rules! __thread_local_inner {
|
||||
|
||||
#[allow(trivial_casts)]
|
||||
#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
|
||||
const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
|
||||
::std::thread::__local::__impl::KeyInner {
|
||||
const _INIT: ::std::thread::__local::KeyInner<$t> = {
|
||||
::std::thread::__local::KeyInner {
|
||||
inner: ::std::cell::UnsafeCell { value: $init },
|
||||
os: ::std::thread::__local::__impl::OsStaticKey {
|
||||
inner: ::std::thread::__local::__impl::OS_INIT_INNER,
|
||||
os: ::std::thread::__local::OsStaticKey {
|
||||
inner: ::std::thread::__local::OS_INIT_INNER,
|
||||
dtor: ::std::option::Option::Some(
|
||||
::std::thread::__local::__impl::destroy_value::<$t>
|
||||
::std::thread::__local::destroy_value::<$t>
|
||||
),
|
||||
},
|
||||
}
|
||||
|
@ -99,6 +99,7 @@
|
||||
//! `println!` and `panic!` for the child thread:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #![allow(unused_must_use)]
|
||||
//! use std::thread;
|
||||
//!
|
||||
//! thread::Builder::new().name("child1".to_string()).spawn(move || {
|
||||
@ -167,14 +168,6 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::__local::{LocalKey, LocalKeyState};
|
||||
|
||||
#[unstable(feature = "scoped_tls",
|
||||
reason = "scoped TLS has yet to have wide enough use to fully consider \
|
||||
stabilizing its interface")]
|
||||
pub use self::__scoped::ScopedKey;
|
||||
|
||||
use prelude::v1::*;
|
||||
|
||||
use any::Any;
|
||||
@ -193,13 +186,19 @@ use time::Duration;
|
||||
// Thread-local storage
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[macro_use]
|
||||
#[doc(hidden)]
|
||||
#[path = "local.rs"] pub mod __local;
|
||||
#[macro_use] mod local;
|
||||
#[macro_use] mod scoped;
|
||||
|
||||
#[macro_use]
|
||||
#[doc(hidden)]
|
||||
#[path = "scoped.rs"] pub mod __scoped;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::local::{LocalKey, LocalKeyState};
|
||||
|
||||
#[unstable(feature = "scoped_tls",
|
||||
reason = "scoped TLS has yet to have wide enough use to fully \
|
||||
consider stabilizing its interface")]
|
||||
pub use self::scoped::ScopedKey;
|
||||
|
||||
#[doc(hidden)] pub use self::local::__impl as __local;
|
||||
#[doc(hidden)] pub use self::scoped::__impl as __scoped;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Builder
|
||||
|
@ -110,7 +110,7 @@ macro_rules! __scoped_thread_local_inner {
|
||||
target_os = "openbsd",
|
||||
target_arch = "aarch64")))]
|
||||
const _INIT: __Key<$t> = __Key {
|
||||
inner: ::std::thread::__scoped::__impl::KeyInner {
|
||||
inner: ::std::thread::__scoped::KeyInner {
|
||||
inner: ::std::cell::UnsafeCell { value: 0 as *mut _ },
|
||||
}
|
||||
};
|
||||
@ -121,8 +121,8 @@ macro_rules! __scoped_thread_local_inner {
|
||||
target_os = "openbsd",
|
||||
target_arch = "aarch64"))]
|
||||
const _INIT: __Key<$t> = __Key {
|
||||
inner: ::std::thread::__scoped::__impl::KeyInner {
|
||||
inner: ::std::thread::__scoped::__impl::OS_INIT,
|
||||
inner: ::std::thread::__scoped::KeyInner {
|
||||
inner: ::std::thread::__scoped::OS_INIT,
|
||||
marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>,
|
||||
}
|
||||
};
|
||||
|
@ -89,7 +89,8 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
|
||||
} else {
|
||||
src = PathBuf::from(&env::args().nth(2).unwrap());
|
||||
}
|
||||
// preprocess the markdown, rerouting markdown references to html references
|
||||
// preprocess the markdown, rerouting markdown references to html
|
||||
// references
|
||||
let mut markdown_data = String::new();
|
||||
try!(File::open(&src.join(&item.path)).and_then(|mut f| {
|
||||
f.read_to_string(&mut markdown_data)
|
||||
@ -135,6 +136,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
|
||||
format!("-o{}", out_path.display()),
|
||||
format!("--html-before-content={}", prelude.display()),
|
||||
format!("--html-after-content={}", postlude.display()),
|
||||
format!("--markdown-playground-url=http://play.rust-lang.org"),
|
||||
format!("--markdown-css={}", item.path_to_root.join("rust-book.css").display()),
|
||||
"--markdown-no-toc".to_string(),
|
||||
];
|
||||
@ -148,6 +150,14 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
|
||||
|
||||
// create index.html from the root README
|
||||
try!(fs::copy(&tgt.join("README.html"), &tgt.join("index.html")));
|
||||
|
||||
// Copy some js for playpen
|
||||
let mut jquery = try!(File::create(tgt.join("jquery.js")));
|
||||
let js = include_bytes!("../librustdoc/html/static/jquery-2.1.0.min.js");
|
||||
try!(jquery.write_all(js));
|
||||
let mut playpen = try!(File::create(tgt.join("playpen.js")));
|
||||
let js = include_bytes!("../librustdoc/html/static/playpen.js");
|
||||
try!(playpen.write_all(js));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -71,4 +71,6 @@ document.addEventListener("DOMContentLoaded", function(event) {
|
||||
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="playpen.js"></script>
|
||||
"#;
|
||||
|
14
src/test/auxiliary/inline-default-methods.rs
Normal file
14
src/test/auxiliary/inline-default-methods.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub trait Foo {
|
||||
fn bar(&self);
|
||||
fn foo(&mut self) {}
|
||||
}
|
@ -8,7 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern crate ext;
|
||||
pub trait Foo {
|
||||
#[doc(hidden)]
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
// @count lib/struct.Struct.html '//*[@id="method.provided"]' 1
|
||||
pub use ext::Struct;
|
||||
impl Foo for i32 {}
|
15
src/test/auxiliary/issue-15318.rs
Normal file
15
src/test/auxiliary/issue-15318.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![doc(html_root_url = "http://example.com/")]
|
||||
|
||||
/// dox
|
||||
#[doc(primitive = "pointer")]
|
||||
pub mod ptr {}
|
@ -8,9 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
extern crate lib;
|
||||
#![doc(html_root_url = "http://example.com")]
|
||||
|
||||
// @has user/fn.foreigner.html //pre 'pub unsafe fn foreigner(cold_as_ice: u32)'
|
||||
pub use lib::foreigner;
|
||||
pub trait Foo {
|
||||
fn foo(&self) {}
|
||||
}
|
15
src/test/auxiliary/issue-20646.rs
Normal file
15
src/test/auxiliary/issue-20646.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub trait Trait {
|
||||
type Output;
|
||||
}
|
||||
|
||||
pub fn fun<T>(_: T) where T: Trait<Output=i32> {}
|
38
src/test/auxiliary/issue-20727.rs
Normal file
38
src/test/auxiliary/issue-20727.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub trait Deref {
|
||||
type Target: ?Sized;
|
||||
|
||||
fn deref<'a>(&'a self) -> &'a Self::Target;
|
||||
}
|
||||
|
||||
pub trait Add<RHS = Self> {
|
||||
type Output;
|
||||
|
||||
fn add(self, rhs: RHS) -> Self::Output;
|
||||
}
|
||||
|
||||
|
||||
pub trait Bar {}
|
||||
pub trait Deref2 {
|
||||
type Target: Bar;
|
||||
|
||||
fn deref(&self) -> Self::Target;
|
||||
}
|
||||
|
||||
pub trait Index<Idx: ?Sized> {
|
||||
type Output: ?Sized;
|
||||
fn index(&self, index: Idx) -> &Self::Output;
|
||||
}
|
||||
|
||||
pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
|
||||
fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
|
||||
}
|
20
src/test/auxiliary/issue-21092.rs
Normal file
20
src/test/auxiliary/issue-21092.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <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 trait Foo {
|
||||
type Bar;
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
pub struct Bar;
|
||||
|
||||
impl Foo for Bar {
|
||||
type Bar = i32;
|
||||
}
|
17
src/test/auxiliary/issue-21801.rs
Normal file
17
src/test/auxiliary/issue-21801.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub struct Foo;
|
||||
|
||||
impl Foo {
|
||||
pub fn new<F>(f: F) -> Foo where F: FnMut() -> i32 {
|
||||
loop {}
|
||||
}
|
||||
}
|
18
src/test/auxiliary/issue-22025.rs
Normal file
18
src/test/auxiliary/issue-22025.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub mod foo {
|
||||
|
||||
pub trait Foo {}
|
||||
pub struct Bar;
|
||||
|
||||
impl Foo for Bar {}
|
||||
|
||||
}
|
13
src/test/auxiliary/issue-23207-1.rs
Normal file
13
src/test/auxiliary/issue-23207-1.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub mod fmt {
|
||||
pub struct Error;
|
||||
}
|
16
src/test/auxiliary/issue-23207-2.rs
Normal file
16
src/test/auxiliary/issue-23207-2.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern crate issue_23207_1;
|
||||
|
||||
pub mod fmt {
|
||||
pub use issue_23207_1::fmt::Error;
|
||||
}
|
||||
|
@ -8,8 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_name="foo"]
|
||||
|
||||
/// ```rust
|
||||
/// assert_eq!(foo::foo(), 1);
|
||||
/// ```
|
||||
|
@ -1,5 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all: lib.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc lib.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc lib.rs
|
@ -1,5 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all: foo.rs bar.rs
|
||||
$(RUSTC) foo.rs --crate-type lib
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc bar.rs -L $(TMPDIR)
|
@ -1,6 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all: lib.rs ext.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTC) ext.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -L $(TMPDIR) -w html -o $(TMPDIR)/doc lib.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc lib.rs
|
@ -1,7 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all: foo.rs bar.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTC) foo.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -L $(TMPDIR) -w html -o $(TMPDIR)/doc bar.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc bar.rs
|
@ -1,8 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all: lib.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTC) lib.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc lib.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -L $(TMPDIR) -w html -o $(TMPDIR)/doc user.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc lib.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc user.rs
|
@ -1,15 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
# FIXME ignore windows
|
||||
ifndef IS_WINDOWS
|
||||
|
||||
all:
|
||||
@echo $(RUSTDOC)
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) --test foo.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc foo.rs
|
||||
|
||||
else
|
||||
all:
|
||||
|
||||
endif
|
@ -1,5 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all: lib.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc lib.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc lib.rs
|
@ -1,5 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all: foo.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc foo.rs
|
@ -1,11 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
# FIXME ignore windows
|
||||
ifndef IS_WINDOWS
|
||||
all:
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo2.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo3.rs
|
||||
else
|
||||
all:
|
||||
endif
|
@ -1,15 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
# FIXME ignore windows
|
||||
ifndef IS_WINDOWS
|
||||
|
||||
source=index.rs
|
||||
|
||||
all:
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc $(source)
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc $(source)
|
||||
|
||||
else
|
||||
all:
|
||||
|
||||
endif
|
@ -1,4 +0,0 @@
|
||||
-include ../tools.mk
|
||||
all:
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc foo.rs
|
@ -1,5 +0,0 @@
|
||||
-include ../tools.mk
|
||||
all:
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc foo.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc qux/mod.rs
|
@ -1,43 +0,0 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
//! Dox
|
||||
// @has src/foo/foo.rs.html
|
||||
// @has foo/index.html '//a/@href' '../src/foo/foo.rs.html'
|
||||
|
||||
pub mod qux;
|
||||
|
||||
// @has foo/bar/index.html '//a/@href' '../../src/foo/foo.rs.html'
|
||||
pub mod bar {
|
||||
|
||||
/// Dox
|
||||
// @has foo/bar/baz/index.html '//a/@href' '../../../src/foo/foo.rs.html'
|
||||
pub mod baz {
|
||||
/// Dox
|
||||
// @has foo/bar/baz/fn.baz.html '//a/@href' '../../../src/foo/foo.rs.html'
|
||||
pub fn baz() { }
|
||||
}
|
||||
|
||||
/// Dox
|
||||
// @has foo/bar/trait.Foobar.html '//a/@href' '../../src/foo/foo.rs.html'
|
||||
pub trait Foobar { fn dummy(&self) { } }
|
||||
|
||||
// @has foo/bar/struct.Foo.html '//a/@href' '../../src/foo/foo.rs.html'
|
||||
pub struct Foo { x: i32, y: u32 }
|
||||
|
||||
// @has foo/bar/fn.prawns.html '//a/@href' '../../src/foo/foo.rs.html'
|
||||
pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { }
|
||||
}
|
||||
|
||||
/// Dox
|
||||
// @has foo/fn.modfn.html '//a/@href' '../src/foo/foo.rs.html'
|
||||
pub fn modfn() { }
|
@ -1,39 +0,0 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Dox
|
||||
// @has src/foo/qux/mod.rs.html
|
||||
// @has foo/qux/index.html '//a/@href' '../../src/foo/qux/mod.rs.html'
|
||||
|
||||
// @has foo/qux/bar/index.html '//a/@href' '../../../src/foo/qux/mod.rs.html'
|
||||
pub mod bar {
|
||||
|
||||
/// Dox
|
||||
// @has foo/qux/bar/baz/index.html '//a/@href' '../../../../src/foo/qux/mod.rs.html'
|
||||
pub mod baz {
|
||||
/// Dox
|
||||
// @has foo/qux/bar/baz/fn.baz.html '//a/@href' '../../../../src/foo/qux/mod.rs.html'
|
||||
pub fn baz() { }
|
||||
}
|
||||
|
||||
/// Dox
|
||||
// @has foo/qux/bar/trait.Foobar.html '//a/@href' '../../../src/foo/qux/mod.rs.html'
|
||||
pub trait Foobar { fn dummy(&self) { } }
|
||||
|
||||
// @has foo/qux/bar/struct.Foo.html '//a/@href' '../../../src/foo/qux/mod.rs.html'
|
||||
pub struct Foo { x: i32, y: u32 }
|
||||
|
||||
// @has foo/qux/bar/fn.prawns.html '//a/@href' '../../../src/foo/qux/mod.rs.html'
|
||||
pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { }
|
||||
}
|
||||
|
||||
/// Dox
|
||||
// @has foo/qux/fn.modfn.html '//a/@href' '../../src/foo/qux/mod.rs.html'
|
||||
pub fn modfn() { }
|
@ -1,5 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all: foo.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc foo.rs
|
@ -1,5 +0,0 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all: foo.rs
|
||||
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs
|
||||
$(HTMLDOCCK) $(TMPDIR)/doc foo.rs
|
@ -10,7 +10,7 @@
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
// @has lib/trait.Index.html
|
||||
// @has assoc_types/trait.Index.html
|
||||
pub trait Index<I: ?Sized> {
|
||||
// @has - '//*[@id="associatedtype.Output"]//code' 'type Output: ?Sized'
|
||||
type Output: ?Sized;
|
19
src/test/rustdoc/default-impl.rs
Normal file
19
src/test/rustdoc/default-impl.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:rustdoc-default-impl.rs
|
||||
// ignore-android
|
||||
|
||||
extern crate rustdoc_default_impl as foo;
|
||||
|
||||
pub use foo::bar;
|
||||
|
||||
pub fn wut<T: bar::Bar>() {
|
||||
}
|
17
src/test/rustdoc/extern-default-method.rs
Normal file
17
src/test/rustdoc/extern-default-method.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:rustdoc-extern-default-method.rs
|
||||
// ignore-android
|
||||
|
||||
extern crate rustdoc_extern_default_method as ext;
|
||||
|
||||
// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]' 1
|
||||
pub use ext::Struct;
|
@ -8,16 +8,19 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:rustdoc-extern-method.rs
|
||||
// ignore-android
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
extern crate foo;
|
||||
extern crate rustdoc_extern_method as foo;
|
||||
|
||||
// @has bar/trait.Foo.html //pre "pub trait Foo"
|
||||
// @has extern_method/trait.Foo.html //pre "pub trait Foo"
|
||||
// @has - '//*[@id="tymethod.foo"]//code' 'extern "rust-call" fn foo'
|
||||
// @has - '//*[@id="tymethod.foo_"]//code' 'extern "rust-call" fn foo_'
|
||||
// @has - '//*[@id="method.foo_"]//code' 'extern "rust-call" fn foo_'
|
||||
pub use foo::Foo;
|
||||
|
||||
// @has bar/trait.Bar.html //pre "pub trait Bar"
|
||||
// @has extern_method/trait.Bar.html //pre "pub trait Bar"
|
||||
pub trait Bar {
|
||||
// @has - '//*[@id="tymethod.bar"]//code' 'extern "rust-call" fn bar'
|
||||
extern "rust-call" fn bar(&self, _: ());
|
22
src/test/rustdoc/ffi.rs
Normal file
22
src/test/rustdoc/ffi.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:rustdoc-ffi.rs
|
||||
// ignore-android
|
||||
|
||||
extern crate rustdoc_ffi as lib;
|
||||
|
||||
// @has ffi/fn.foreigner.html //pre 'pub unsafe extern fn foreigner(cold_as_ice: u32)'
|
||||
pub use lib::foreigner;
|
||||
|
||||
extern "C" {
|
||||
// @has ffi/fn.another.html //pre 'pub unsafe extern fn another(cold_as_ice: u32)'
|
||||
pub fn another(cold_as_ice: u32);
|
||||
}
|
@ -8,8 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_name="foo"]
|
||||
|
||||
/// The '# ' lines should be removed from the output, but the #[derive] should be
|
||||
/// retained.
|
||||
///
|
||||
@ -31,5 +29,5 @@
|
||||
/// ```
|
||||
pub fn foo() {}
|
||||
|
||||
// @!has foo/fn.foo.html invisible
|
||||
// @!has hidden_line/fn.foo.html invisible
|
||||
// @matches - //pre "#\[derive\(PartialEq\)\] // Bar"
|
19
src/test/rustdoc/inline-default-methods.rs
Normal file
19
src/test/rustdoc/inline-default-methods.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:inline-default-methods.rs
|
||||
// ignore-android
|
||||
|
||||
extern crate inline_default_methods;
|
||||
|
||||
// @has inline_default_methods/trait.Foo.html
|
||||
// @has - '//*[@class="rust trait"]' 'fn bar(&self);'
|
||||
// @has - '//*[@class="rust trait"]' 'fn foo(&mut self) { ... }'
|
||||
pub use inline_default_methods::Foo;
|
26
src/test/rustdoc/issue-13698.rs
Normal file
26
src/test/rustdoc/issue-13698.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:issue-13698.rs
|
||||
// ignore-android
|
||||
|
||||
extern crate issue_13698;
|
||||
|
||||
pub struct Foo;
|
||||
// @!has issue_13698/struct.Foo.html '//*[@id="method.foo"]' 'fn foo'
|
||||
impl issue_13698::Foo for Foo {}
|
||||
|
||||
pub trait Bar {
|
||||
#[doc(hidden)]
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
// @!has issue_13698/struct.Foo.html '//*[@id="method.foo"]' 'fn bar'
|
||||
impl Bar for Foo {}
|
13
src/test/rustdoc/issue-15169.rs
Normal file
13
src/test/rustdoc/issue-15169.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// @has issue_15169/struct.Foo.html '//*[@id="method.eq"]' 'fn eq'
|
||||
#[derive(PartialEq)]
|
||||
pub struct Foo;
|
22
src/test/rustdoc/issue-15318-2.rs
Normal file
22
src/test/rustdoc/issue-15318-2.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:issue-15318.rs
|
||||
// ignore-android
|
||||
|
||||
extern crate issue_15318;
|
||||
|
||||
pub use issue_15318::ptr;
|
||||
|
||||
// @has issue_15318_2/fn.bar.html \
|
||||
// '//*[@href="primitive.pointer.html"]' \
|
||||
// '*mut T'
|
||||
pub fn bar<T>(ptr: *mut T) {}
|
||||
|
15
src/test/rustdoc/issue-15318-3.rs
Normal file
15
src/test/rustdoc/issue-15318-3.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// @has issue_15318_3/primitive.pointer.html
|
||||
|
||||
/// dox
|
||||
#[doc(primitive = "pointer")]
|
||||
pub mod ptr {}
|
22
src/test/rustdoc/issue-15318.rs
Normal file
22
src/test/rustdoc/issue-15318.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:issue-15318.rs
|
||||
// ignore-android
|
||||
|
||||
#![feature(no_std)]
|
||||
#![no_std]
|
||||
|
||||
extern crate issue_15318;
|
||||
|
||||
// @has issue_15318/fn.bar.html \
|
||||
// '//*[@href="http://example.com/issue_15318/primitive.pointer.html"]' \
|
||||
// '*mut T'
|
||||
pub fn bar<T>(ptr: *mut T) {}
|
15
src/test/rustdoc/issue-15347.rs
Normal file
15
src/test/rustdoc/issue-15347.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2105 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.
|
||||
|
||||
// compile-flags:--no-defaults --passes "collapse-docs" --passes "unindent-comments"
|
||||
|
||||
// @has issue_15347/fn.foo.html
|
||||
#[doc(hidden)]
|
||||
pub fn foo() {}
|
19
src/test/rustdoc/issue-16019.rs
Normal file
19
src/test/rustdoc/issue-16019.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
macro_rules! define_struct {
|
||||
($rounds:expr) => (
|
||||
struct Struct {
|
||||
sk: [u32; $rounds + 1]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
define_struct!(2);
|
18
src/test/rustdoc/issue-16265-1.rs
Normal file
18
src/test/rustdoc/issue-16265-1.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub struct Foo;
|
||||
|
||||
// @has issue_16265_1/traits/index.html '[src]'
|
||||
pub mod traits {
|
||||
impl PartialEq for super::Foo {
|
||||
fn eq(&self, _: &super::Foo) -> bool { true }
|
||||
}
|
||||
}
|
15
src/test/rustdoc/issue-16265-2.rs
Normal file
15
src/test/rustdoc/issue-16265-2.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
// @has issue_16265_2/index.html '[src]'
|
||||
|
||||
trait Y {}
|
||||
impl Y for Option<u32>{}
|
21
src/test/rustdoc/issue-17476.rs
Normal file
21
src/test/rustdoc/issue-17476.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:issue-17476.rs
|
||||
// ignore-android
|
||||
|
||||
extern crate issue_17476;
|
||||
|
||||
pub struct Foo;
|
||||
|
||||
// @has issue_17476/struct.Foo.html \
|
||||
// '//*[@href="http://example.com/issue_17476/trait.Foo.html#method.foo"]' \
|
||||
// 'foo'
|
||||
impl issue_17476::Foo for Foo {}
|
19
src/test/rustdoc/issue-18199.rs
Normal file
19
src/test/rustdoc/issue-18199.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags:--test
|
||||
|
||||
#![doc(test(attr(feature(staged_api))))]
|
||||
|
||||
/// ```
|
||||
/// #![staged_api]
|
||||
/// fn main() {}
|
||||
/// ```
|
||||
pub fn foo() {}
|
30
src/test/rustdoc/issue-19055.rs
Normal file
30
src/test/rustdoc/issue-19055.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// @has issue_19055/trait.Any.html
|
||||
pub trait Any {}
|
||||
|
||||
impl<'any> Any + 'any {
|
||||
// @has - '//*[@id="method.is"]' 'fn is'
|
||||
pub fn is<T: 'static>(&self) -> bool { loop {} }
|
||||
|
||||
// @has - '//*[@id="method.downcast_ref"]' 'fn downcast_ref'
|
||||
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> { loop {} }
|
||||
|
||||
// @has - '//*[@id="method.downcast_mut"]' 'fn downcast_mut'
|
||||
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> { loop {} }
|
||||
}
|
||||
|
||||
pub trait Foo {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
// @has - '//*[@id="method.foo"]' 'fn foo'
|
||||
impl Foo for Any {}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user