Closes #9333.
# version-string calculation
CFG_GIT_DIR := $(CFG_SRC_DIR).git
-CFG_RELEASE = 0.8-pre
+CFG_RELEASE = 0.8
CFG_VERSION = $(CFG_RELEASE)
# windows exe's need numeric versions - don't use anything but
# numbers and dots here
CFG_LIBSYNTAX_$(1) :=$(call CFG_LIB_NAME_$(1),syntax)
CFG_LIBRUSTPKG_$(1) :=$(call CFG_LIB_NAME_$(1),rustpkg)
CFG_LIBRUSTDOC_$(1) :=$(call CFG_LIB_NAME_$(1),rustdoc)
-CFG_LIBRUSTDOCNG_$(1) :=$(call CFG_LIB_NAME_$(1),rustdoc_ng)
CFG_LIBRUSTI_$(1) :=$(call CFG_LIB_NAME_$(1),rusti)
CFG_LIBRUST_$(1) :=$(call CFG_LIB_NAME_$(1),rust)
LIBSYNTAX_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),syntax)
LIBRUSTPKG_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustpkg)
LIBRUSTDOC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustdoc)
-LIBRUSTDOCNG_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustdoc_ng)
LIBRUSTI_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rusti)
LIBRUST_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rust)
EXTRALIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),extra)
LIBSYNTAX_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),syntax)
LIBRUSTPKG_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustpkg)
LIBRUSTDOC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc)
-LIBRUSTDOCNG_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc_ng)
LIBRUSTI_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rusti)
LIBRUST_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rust)
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
$$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(3)) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
- $$(HBIN$(1)_H_$(3))/rustdoc_ng$$(X_$(3)) \
$$(HBIN$(1)_H_$(3))/rusti$$(X_$(3)) \
$$(HBIN$(1)_H_$(3))/rust$$(X_$(3)) \
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTPKG_$(3)) \
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTDOC_$(3)) \
- $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(3)) \
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTI_$(3)) \
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUST_$(3)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTI_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUST_$(2))
[tutorial]: http://static.rust-lang.org/doc/tutorial.html
[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
-[win-exe]: http://static.rust-lang.org/dist/rust-0.7-install.exe
+[win-exe]: http://static.rust-lang.org/dist/rust-0.8-install.exe
### Linux / OS X
To build from the [tarball] do:
- $ curl -O http://static.rust-lang.org/dist/rust-0.7.tar.gz
- $ tar -xzf rust-0.7.tar.gz
- $ cd rust-0.7
+ $ curl -O http://static.rust-lang.org/dist/rust-0.8.tar.gz
+ $ tar -xzf rust-0.8.tar.gz
+ $ cd rust-0.8
Or to build from the [repo] do:
4. Enjoy!
[repo]: https://github.com/mozilla/rust
-[tarball]: http://static.rust-lang.org/dist/rust-0.7.tar.gz
-[tutorial]: http://static.rust-lang.org/doc/0.7/tutorial.html
+[tarball]: http://static.rust-lang.org/dist/rust-0.8.tar.gz
+[tutorial]: http://static.rust-lang.org/doc/0.8/tutorial.html
## Notes
* The runtime uses jemalloc for allocations.
* Segmented stacks are temporarily disabled as part of the transition to
the new runtime. Stack overflows are possible!
- * A new documentation backend, rustdoc_ng, is available for use
+ * A new documentation backend, rustdoc_ng, is available for use. It is
+ still invoked through the normal `rustdoc` command.
Version 0.7 (July 2013)
-----------------------
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-08-12 02:06+0900\n"
"PO-Revision-Date: 2013-08-05 19:40+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-07-30 07:07+0900\n"
"PO-Revision-Date: 2013-07-28 20:32+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-07-22 23:37+0900\n"
"PO-Revision-Date: 2013-07-28 20:32+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-08-05 19:40+0900\n"
"PO-Revision-Date: 2013-07-28 20:32+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-08-10 07:44+0900\n"
"PO-Revision-Date: 2013-07-22 23:37+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-07-28 20:32+0900\n"
"PO-Revision-Date: 2013-07-28 20:32+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-08-08 22:27+0900\n"
"PO-Revision-Date: 2013-07-28 20:32+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-08-12 02:06+0900\n"
"PO-Revision-Date: 2013-08-08 22:27+0900\n"
"Last-Translator: Automatically generated\n"
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-08-12 02:06+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-07-30 07:07+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-07-22 23:37+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-08-05 19:40+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-08-10 07:44+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-07-22 23:37+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-08-08 22:27+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.8-pre\n"
+"Project-Id-Version: Rust 0.8\n"
"POT-Creation-Date: 2013-08-12 02:06+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
#. type: Plain text
#: doc/tutorial.md:108
msgid ""
-"~~~~ {.notrust} $ curl -O http://static.rust-lang.org/dist/rust-0.7.tar.gz $ "
-"tar -xzf rust-0.7.tar.gz $ cd rust-0.7 $ ./configure $ make && make install "
+"~~~~ {.notrust} $ curl -O http://static.rust-lang.org/dist/rust-0.8.tar.gz $ "
+"tar -xzf rust-0.8.tar.gz $ cd rust-0.8 $ ./configure $ make && make install "
"~~~~"
msgstr ""
#. type: Plain text
#: doc/tutorial.md:123
msgid ""
-"[tarball]: http://static.rust-lang.org/dist/rust-0.7.tar.gz [win-exe]: "
-"http://static.rust-lang.org/dist/rust-0.7-install.exe"
+"[tarball]: http://static.rust-lang.org/dist/rust-0.8.tar.gz [win-exe]: "
+"http://static.rust-lang.org/dist/rust-0.8-install.exe"
msgstr ""
#. type: Plain text
should work.
~~~~ {.notrust}
-$ curl -O http://static.rust-lang.org/dist/rust-0.7.tar.gz
-$ tar -xzf rust-0.7.tar.gz
-$ cd rust-0.7
+$ curl -O http://static.rust-lang.org/dist/rust-0.8.tar.gz
+$ tar -xzf rust-0.8.tar.gz
+$ cd rust-0.8
$ ./configure
$ make && make install
~~~~
`rusti`, the Rust REPL; and `rust`, a tool which acts both as a unified
interface for them, and for a few common command line scenarios.
-[tarball]: http://static.rust-lang.org/dist/rust-0.7.tar.gz
-[win-exe]: http://static.rust-lang.org/dist/rust-0.7-install.exe
+[tarball]: http://static.rust-lang.org/dist/rust-0.8.tar.gz
+[win-exe]: http://static.rust-lang.org/dist/rust-0.8-install.exe
## Compiling your first program
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustpkg$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/serializer$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc$(X_$(2))
- $(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc_ng$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rusti$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rust$(X_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTPKG_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTDOC_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTDOCNG_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUNTIME_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_STDLIB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_EXTRALIB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBSYNTAX_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTPKG_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOC_GLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOCNG_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTI_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUST_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUSTLLVM_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/serializer$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc$(X_$(2))
- $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc_ng$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rusti$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rust$(X_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBSYNTAX_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTPKG_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTDOC_GLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTDOCNG_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTI_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUST_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(2))
libsyntax \
rt \
librustdoc \
- rustdoc_ng \
rustllvm \
snapshots.txt \
test) \
# The rustdoc executable
RUSTDOC = $(HBIN2_H_$(CFG_BUILD_TRIPLE))/rustdoc$(X_$(CFG_BUILD_TRIPLE))
-RUSTDOC_NG = $(HBIN2_H_$(CFG_BUILD_TRIPLE))/rustdoc_ng$(X_$(CFG_BUILD_TRIPLE))
# The library documenting macro
-# $(1) - The output directory
+# $(1) - The crate name (std/extra)
# $(2) - The crate file
-# $(3) - The crate soruce files
+# $(3) - The relevant host build triple (to depend on libstd)
define libdoc
-doc/$(1)/index.html: $(2) $(3) $$(RUSTDOC) doc/$(1)/rust.css
+doc/$(1)/index.html: $$(RUSTDOC) $$(TLIB2_T_$(3)_H_$(3))/$(CFG_STDLIB_$(3))
@$$(call E, rustdoc: $$@)
- $(Q)$(RUSTDOC) $(2) --output-dir=doc/$(1)
-
-doc/$(1)/rust.css: rust.css
- @$$(call E, cp: $$@)
- $(Q)cp $$< $$@
+ $(Q)$(RUSTDOC) html $(2)
DOCS += doc/$(1)/index.html
endef
-# The "next generation" library documenting macro
-# $(1) - The crate name (std/extra)
-# $(2) - The crate file
-# $(3) - The relevant host build triple (to depend on libstd)
-define libdocng
-doc/ng/$(1)/index.html: $$(RUSTDOC_NG) $$(TLIB2_T_$(3)_H_$(3))/$(CFG_STDLIB_$(3))
- @$$(call E, rustdoc_ng: $$@)
- $(Q)$(RUSTDOC_NG) html $(2) -o doc/ng
-
-DOCS += doc/ng/$(1)/index.html
-endef
-
-$(eval $(call libdoc,std,$(STDLIB_CRATE),$(STDLIB_INPUTS)))
-$(eval $(call libdoc,extra,$(EXTRALIB_CRATE),$(EXTRALIB_INPUTS)))
-$(eval $(call libdocng,std,$(STDLIB_CRATE),$(CFG_BUILD_TRIPLE)))
-$(eval $(call libdocng,extra,$(EXTRALIB_CRATE),$(CFG_BUILD_TRIPLE)))
+$(eval $(call libdoc,std,$(STDLIB_CRATE),$(CFG_BUILD_TRIPLE)))
+$(eval $(call libdoc,extra,$(EXTRALIB_CRATE),$(CFG_BUILD_TRIPLE)))
endif
$$(Q)$$(call INSTALL_LIB,$$(LIBSYNTAX_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTPKG_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTDOC_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBRUSTDOCNG_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTI_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBRUST_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,libmorestack.a)
$(Q)$(call INSTALL,$(HB2),$(PHB),rustc$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustpkg$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(X_$(CFG_BUILD_TRIPLE)))
- $(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc_ng$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rusti$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rust$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(STDLIB_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBRUST_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTDOC_GLOB_$(CFG_BUILD_TRIPLE)))
- $(Q)$(call INSTALL_LIB,$(LIBRUSTDOCNG_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(S)/man, $(PREFIX_ROOT)/share/man/man1,rust.1)
$(Q)rm -f $(PHB)/rusti$(X_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHB)/rust$(X_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHB)/rustdoc$(X_$(CFG_BUILD_TRIPLE))
- $(Q)rm -f $(PHB)/rustdoc_ng$(X_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHL)/$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHL)/$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE))
$(Q)for i in \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTDOC_GLOB_$(CFG_BUILD_TRIPLE))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTDOCNG_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTI_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUST_GLOB_$(CFG_BUILD_TRIPLE))) \
; \
rt/rust_rng.cpp \
rt/rust_upcall.cpp \
rt/rust_uv.cpp \
- rt/isaac/randport.cpp \
rt/miniz.cpp \
rt/memory_region.cpp \
rt/boxed_region.cpp \
# The names of crates that must be tested
TEST_TARGET_CRATES = std extra
-TEST_HOST_CRATES = rust rusti rustpkg rustc rustdoc rustdocng syntax
+TEST_HOST_CRATES = rust rusti rustpkg rustc rustdoc syntax
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
# Markdown files under doc/ that should have their code extracted and run
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
-$(3)/stage$(1)/test/rustdocngtest-$(2)$$(X_$(2)): \
- $$(RUSTDOCNG_LIB) $$(RUSTDOCNG_INPUTS) \
- $$(SREQ$(1)_T_$(2)_H_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
-
endef
$(foreach host,$(CFG_HOST_TRIPLES), \
RUSTDOC_LIB := $(S)src/librustdoc/rustdoc.rs
RUSTDOC_INPUTS := $(wildcard $(S)src/librustdoc/*.rs)
-# rustdoc_ng, the next generation documentation tool
-
-RUSTDOCNG_LIB := $(S)src/rustdoc_ng/rustdoc_ng.rs
-RUSTDOCNG_INPUTS := $(wildcard $(S)src/rustdoc_ng/*.rs)
-
# Rusti, the JIT REPL
RUSTI_LIB := $(S)src/librusti/rusti.rs
RUSTI_INPUTS := $(wildcard $(S)src/librusti/*.rs)
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rustdoc -o $$@ $$<
-$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(4)): \
- $$(RUSTDOCNG_LIB) $$(RUSTDOCNG_INPUTS) \
- $$(SREQ$(1)_T_$(4)_H_$(3)) \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) \
- | $$(TLIB$(1)_T_$(4)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOCNG_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) --out-dir $$(@D) $$< && touch $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOCNG_GLOB_$(4)),$$(notdir $$@))
-
-$$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc_ng$$(X_$(4)): \
- $$(DRIVER_CRATE) \
- $$(TSREQ$(1)_T_$(4)_H_$(3)) \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(4)) \
- | $$(TBIN$(1)_T_$(4)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rustdoc_ng -o $$@ $$<
-
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)): \
$$(RUSTI_LIB) $$(RUSTI_INPUTS) \
$$(SREQ$(1)_T_$(4)_H_$(3)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)) \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(4)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) \
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
-$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTDOCNG_$(4)): \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOCNG_$(4)) \
- $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
- $$(HSREQ$(2)_H_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOCNG_GLOB_$(4)),$$(notdir $$@))
- $$(Q)cp $$< $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOCNG_GLOB_$(4)),$$(notdir $$@))
- $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTDOCNG_GLOB_$(4)) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTDOCNG_DSYM_GLOB_$(4))) \
- $$(HLIB$(2)_H_$(4))
-
-$$(HBIN$(2)_H_$(4))/rustdoc_ng$$(X_$(4)): \
- $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc_ng$$(X_$(4)) \
- $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTDOCNG_$(4)) \
- $$(HSREQ$(2)_H_$(4)) \
- | $$(HBIN$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTI_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
<!ENTITY rustIdent "[a-zA-Z_][a-zA-Z_0-9]*">
<!ENTITY rustIntSuf "([iu](8|16|32|64)?)?">
]>
-<language name="Rust" version="0.8-pre" kateversion="2.4" section="Sources" extensions="*.rs;*.rc" mimetype="text/x-rust" priority="15">
+<language name="Rust" version="0.8" kateversion="2.4" section="Sources" extensions="*.rs;*.rc" mimetype="text/x-rust" priority="15">
<highlighting>
<list name="fn">
<item> fn </item>
#[test]
fn test_base64_random() {
- use std::rand::{task_rng, random, RngUtil};
+ use std::rand::{task_rng, random, Rng};
use std::vec;
do 1000.times {
- let times = task_rng().gen_uint_range(1, 100);
+ let times = task_rng().gen_integer_range(1u, 100);
let v = vec::from_fn(times, |_| random::<u8>());
assert_eq!(v.to_base64(STANDARD).from_base64().unwrap(), v);
}
mod bench {
use std::container::MutableMap;
use std::{vec, rand};
- use std::rand::RngUtil;
+ use std::rand::Rng;
use test::BenchHarness;
pub fn insert_rand_n<M:MutableMap<uint,uint>>(n: uint,
#[cfg(test)]
mod test {
- use std::rand::IsaacRng;
- use std::rand::RngUtil;
+ use std::rand::{IsaacRng, Rng};
use std::vec;
use cryptoutil::{add_bytes_to_bits, add_bytes_to_bits_tuple};
digest.reset();
while count < total_size {
- let next: uint = rng.gen_uint_range(0, 2 * blocksize + 1);
+ let next: uint = rng.gen_integer_range(0, 2 * blocksize + 1);
let remaining = total_size - count;
let size = if next > remaining { remaining } else { next };
digest.input(buffer.slice_to(size));
*/
#[link(name = "extra",
- vers = "0.8-pre",
+ vers = "0.8",
uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297",
url = "https://github.com/mozilla/rust/tree/master/src/libextra")];
mod tests {
use super::*;
use std::rand;
- use std::rand::RngUtil;
+ use std::rand::Rng;
#[test]
fn test_flate_round_trip() {
let mut r = rand::rng();
let mut words = ~[];
do 20.times {
- let range = r.gen_uint_range(1, 10);
- words.push(r.gen_bytes(range));
+ let range = r.gen_integer_range(1u, 10);
+ words.push(r.gen_vec::<u8>(range));
}
do 20.times {
let mut input = ~[];
use std::int;
use std::num;
use std::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable};
-use std::rand::{Rng, RngUtil};
+use std::rand::Rng;
use std::str;
use std::uint;
use std::vec;
mod test_tim_sort {
use sort::tim_sort;
- use std::rand::RngUtil;
+ use std::rand::Rng;
use std::rand;
use std::vec;
use sort::*;
- use std::rand::RngUtil;
+ use std::rand::Rng;
use std::rand;
use std::vec;
isSorted(arr);
do 3.times {
- let i1 = rng.gen_uint_range(0, n);
- let i2 = rng.gen_uint_range(0, n);
+ let i1 = rng.gen_integer_range(0u, n);
+ let i2 = rng.gen_integer_range(0u, n);
arr.swap(i1, i2);
}
tim_sort(arr); // 3sort
isSorted(arr);
do (n/100).times {
- let idx = rng.gen_uint_range(0, n);
+ let idx = rng.gen_integer_range(0u, n);
arr[idx] = rng.gen();
}
tim_sort(arr);
isSorted(arr);
do 3.times {
- let i1 = rng.gen_uint_range(0, n);
- let i2 = rng.gen_uint_range(0, n);
+ let i1 = rng.gen_integer_range(0u, n);
+ let i2 = rng.gen_integer_range(0u, n);
arr.swap(i1, i2);
}
tim_sort(arr); // 3sort
isSorted(arr);
do (n/100).times {
- let idx = rng.gen_uint_range(0, n);
+ let idx = rng.gen_integer_range(0u, n);
arr[idx] = @rng.gen();
}
tim_sort(arr);
use std::os;
-use std::rand::RngUtil;
+use std::rand::Rng;
use std::rand;
/// Attempts to make a temporary directory inside of `tmpdir` whose name will
pub fn mkdtemp(tmpdir: &Path, suffix: &str) -> Option<Path> {
let mut r = rand::rng();
for _ in range(0u, 1000) {
- let p = tmpdir.push(r.gen_str(16) + suffix);
+ let p = tmpdir.push(r.gen_ascii_str(16) + suffix);
if os::make_dir(&p, 0x1c0) { // 700
return Some(p);
}
use super::*;
- use std::rand::RngUtil;
+ use std::rand::Rng;
use std::rand;
#[test]
}
do 30.times {
- let r = rng.gen_uint_range(0, ctrl.len());
+ let r = rng.gen_integer_range(0, ctrl.len());
let (key, _) = ctrl.remove(r);
assert!(map.remove(&key));
check_structure(&map);
use std::container::Container;
use std::to_str::ToStr;
use std::rand;
-use std::rand::RngUtil;
+use std::rand::Rng;
use std::cmp::Eq;
use std::cast::{transmute,transmute_copy};
/// of random numbers. Use the rand::Rand trait to supply
/// a custom generator if required.
pub fn new_v4() -> Uuid {
- let ub = rand::task_rng().gen_bytes(16);
+ let ub = rand::task_rng().gen_vec(16);
let mut uuid = Uuid{ bytes: [0, .. 16] };
vec::bytes::copy_memory(uuid.bytes, ub, 16);
uuid.set_variant(VariantRFC4122);
impl rand::Rand for Uuid {
#[inline]
fn rand<R: rand::Rng>(rng: &mut R) -> Uuid {
- let ub = rng.gen_bytes(16);
+ let ub = rng.gen_vec(16);
let mut uuid = Uuid{ bytes: [0, .. 16] };
vec::bytes::copy_memory(uuid.bytes, ub, 16);
uuid.set_variant(VariantRFC4122);
// FIXME #2238 Make run only accept source that emits an executable
#[link(name = "rust",
- vers = "0.8-pre",
+ vers = "0.8",
uuid = "4a24da33-5cc8-4037-9352-2cbe9bd9d27c",
url = "https://github.com/mozilla/rust/tree/master/src/rust")];
cmd: "doc",
action: CallMain("rustdoc", rustdoc::main_args),
usage_line: "generate documentation from doc comments",
- usage_full: UsgCall(rustdoc::config::usage),
+ usage_full: UsgCall(rustdoc_help),
},
Command {
cmd: "pkg",
rustc::usage(os::args()[0].clone())
}
+fn rustdoc_help() {
+ rustdoc::usage(os::args()[0].clone())
+}
+
fn find_cmd(command_string: &str) -> Option<Command> {
do COMMANDS.iter().find |command| {
command.cmd == command_string
use syntax::fold;
use syntax::opt_vec;
-static STD_VERSION: &'static str = "0.8-pre";
+static STD_VERSION: &'static str = "0.8";
pub fn maybe_inject_libstd_ref(sess: Session, crate: @ast::Crate)
-> @ast::Crate {
path_node(~[id_extra]),
ast::DUMMY_NODE_ID))])
} else {
- let mi = attr::mk_name_value_item_str(@"vers", @"0.8-pre");
+ let mi = attr::mk_name_value_item_str(@"vers", @"0.8");
ast::view_item_extern_mod(id_extra, None, ~[mi], ast::DUMMY_NODE_ID)
};
ast::view_item {
// except according to those terms.
#[link(name = "rustc",
- vers = "0.8-pre",
+ vers = "0.8",
uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf",
url = "https://github.com/mozilla/rust/tree/master/src/rustc")];
+++ /dev/null
-// Copyright 2012-2013 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.
-
-/*!
-Provides all access to AST-related, non-sendable info
-
-Rustdoc is intended to be parallel, and the rustc AST is filled with
-shared boxes. The AST service attempts to provide a single place to
-query AST-related information, shielding the rest of Rustdoc from its
-non-sendableness.
-*/
-
-
-use parse;
-
-use std::cell::Cell;
-use std::comm::{stream, SharedChan, Port};
-use std::task;
-use rustc::driver::driver;
-use rustc::driver::session::Session;
-use rustc::driver::session::{basic_options, options};
-use rustc::front;
-use syntax::ast;
-use syntax::ast_map;
-use syntax::ast_util;
-use syntax;
-
-pub struct Ctxt {
- ast: @ast::Crate,
- ast_map: ast_map::map
-}
-
-type SrvOwner<'self,T> = &'self fn(srv: Srv) -> T;
-pub type CtxtHandler<T> = ~fn(ctxt: Ctxt) -> T;
-type Parser = ~fn(Session, s: @str) -> @ast::Crate;
-
-enum Msg {
- HandleRequest(~fn(Ctxt)),
- Exit
-}
-
-#[deriving(Clone)]
-pub struct Srv {
- ch: SharedChan<Msg>
-}
-
-pub fn from_str<T>(source: ~str, owner: SrvOwner<T>) -> T {
- run(owner, source.clone(), parse::from_str_sess)
-}
-
-pub fn from_file<T>(file: ~str, owner: SrvOwner<T>) -> T {
- run(owner, file.clone(), |sess, f| parse::from_file_sess(sess, &Path(f)))
-}
-
-fn run<T>(owner: SrvOwner<T>, source: ~str, parse: Parser) -> T {
-
- let (po, ch) = stream();
-
- let source = Cell::new(source);
- let parse = Cell::new(parse);
- do task::spawn {
- act(&po, source.take().to_managed(), parse.take());
- }
-
- let srv_ = Srv {
- ch: SharedChan::new(ch)
- };
-
- let res = owner(srv_.clone());
- srv_.ch.send(Exit);
- res
-}
-
-fn act(po: &Port<Msg>, source: @str, parse: Parser) {
- let sess = build_session();
-
- let ctxt = build_ctxt(
- sess,
- parse(sess, source)
- );
-
- let mut keep_going = true;
- while keep_going {
- match po.recv() {
- HandleRequest(f) => {
- f(ctxt);
- }
- Exit => {
- keep_going = false;
- }
- }
- }
-}
-
-pub fn exec<T:Send>(
- srv: Srv,
- f: ~fn(ctxt: Ctxt) -> T
-) -> T {
- let (po, ch) = stream();
- let msg = HandleRequest(|ctxt| ch.send(f(ctxt)));
- srv.ch.send(msg);
- po.recv()
-}
-
-fn assign_node_ids(crate: @ast::Crate) -> @ast::Crate {
- let next_id = @mut 0;
- let fold = ast_util::node_id_assigner(|| {
- let i = *next_id;
- *next_id += 1;
- i
- });
- @fold.fold_crate(crate)
-}
-
-fn build_ctxt(sess: Session,
- ast: @ast::Crate) -> Ctxt {
-
- use rustc::front::config;
-
- let ast = syntax::ext::expand::inject_std_macros(sess.parse_sess,
- sess.opts.cfg.clone(),
- ast);
- let ast = config::strip_unconfigured_items(ast);
- let ast = syntax::ext::expand::expand_crate(sess.parse_sess,
- sess.opts.cfg.clone(),
- ast);
- let ast = front::test::modify_for_testing(sess, ast);
- let ast = assign_node_ids(ast);
- let ast_map = ast_map::map_crate(sess.diagnostic(), ast);
-
- Ctxt {
- ast: ast,
- ast_map: ast_map,
- }
-}
-
-fn build_session() -> Session {
- let sopts: @options = basic_options();
- let emitter = syntax::diagnostic::emit;
-
- let session = driver::build_session(sopts, emitter);
- session
-}
-
-#[test]
-fn should_prune_unconfigured_items() {
- let source = ~"#[cfg(shut_up_and_leave_me_alone)]fn a() { }";
- do from_str(source) |srv| {
- do exec(srv) |ctxt| {
- // one item: the __std_macros secret module
- assert_eq!(ctxt.ast.module.items.len(), 1);
- }
- }
-}
-
-#[test]
-fn srv_should_build_ast_map() {
- let source = ~"fn a() { }";
- do from_str(source) |srv| {
- do exec(srv) |ctxt| {
- assert!(!ctxt.ast_map.is_empty())
- };
- }
-}
-
-#[test]
-fn should_ignore_external_import_paths_that_dont_exist() {
- let source = ~"use forble; use forble::bippy;";
- from_str(source, |_srv| { } )
-}
-
-#[test]
-fn srv_should_return_request_result() {
- let source = ~"fn a() { }";
- do from_str(source) |srv| {
- let result = exec(srv, |_ctxt| 1000 );
- assert_eq!(result, 1000);
- }
-}
+++ /dev/null
-// Copyright 2012-2013 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.
-
-/*!
-Attribute parsing
-
-The attribute parser provides methods for pulling documentation out of
-an AST's attributes.
-*/
-
-
-use syntax::ast;
-use syntax::attr;
-use syntax::attr::{AttrMetaMethods, AttributeMethods};
-
-pub struct CrateAttrs {
- name: Option<~str>
-}
-
-fn doc_metas(attrs: ~[ast::Attribute]) -> ~[@ast::MetaItem] {
- attrs.iter()
- .filter(|at| "doc" == at.name())
- .map(|at| at.desugar_doc().meta())
- .collect()
-}
-
-pub fn parse_crate(attrs: ~[ast::Attribute]) -> CrateAttrs {
- let link_metas = attr::find_linkage_metas(attrs);
- let name = attr::last_meta_item_value_str_by_name(link_metas, "name");
-
- CrateAttrs {
- name: name.map(|s| s.to_owned())
- }
-}
-
-pub fn parse_desc(attrs: ~[ast::Attribute]) -> Option<~str> {
- let doc_strs = do doc_metas(attrs).move_iter().filter_map |meta| {
- meta.value_str()
- }.collect::<~[@str]>();
- if doc_strs.is_empty() {
- None
- } else {
- Some(doc_strs.connect("\n"))
- }
-}
-
-pub fn parse_hidden(attrs: ~[ast::Attribute]) -> bool {
- let r = doc_metas(attrs);
- do r.iter().any |meta| {
- match meta.meta_item_list() {
- Some(metas) => attr::contains_name(metas, "hidden"),
- None => false
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use syntax::ast;
- use syntax;
- use super::{parse_hidden, parse_crate, parse_desc};
-
- fn parse_attributes(source: @str) -> ~[ast::Attribute] {
- use syntax::parse;
- use syntax::parse::attr::parser_attr;
-
- let parse_sess = syntax::parse::new_parse_sess(None);
- let parser = parse::new_parser_from_source_str(
- parse_sess, ~[], @"-", source);
-
- parser.parse_outer_attributes()
- }
-
-
- #[test]
- fn should_extract_crate_name_from_link_attribute() {
- let source = @"#[link(name = \"snuggles\")]";
- let attrs = parse_attributes(source);
- let attrs = parse_crate(attrs);
- assert!(attrs.name == Some(~"snuggles"));
- }
-
- #[test]
- fn should_not_extract_crate_name_if_no_link_attribute() {
- let source = @"";
- let attrs = parse_attributes(source);
- let attrs = parse_crate(attrs);
- assert!(attrs.name == None);
- }
-
- #[test]
- fn should_not_extract_crate_name_if_no_name_value_in_link_attribute() {
- let source = @"#[link(whatever)]";
- let attrs = parse_attributes(source);
- let attrs = parse_crate(attrs);
- assert!(attrs.name == None);
- }
-
- #[test]
- fn parse_desc_should_handle_undocumented_mods() {
- let source = @"";
- let attrs = parse_attributes(source);
- let attrs = parse_desc(attrs);
- assert!(attrs == None);
- }
-
- #[test]
- fn parse_desc_should_parse_simple_doc_attributes() {
- let source = @"#[doc = \"basic\"]";
- let attrs = parse_attributes(source);
- let attrs = parse_desc(attrs);
- assert!(attrs == Some(~"basic"));
- }
-
- #[test]
- fn should_parse_hidden_attribute() {
- let source = @"#[doc(hidden)]";
- let attrs = parse_attributes(source);
- assert!(parse_hidden(attrs) == true);
- }
-
- #[test]
- fn should_parse_hidden_attribute_with_other_docs() {
- let source = @"#[doc = \"foo\"] #[doc(hidden)] #[doc = \"foo\"]";
- let attrs = parse_attributes(source);
- assert!(parse_hidden(attrs) == true);
- }
-
- #[test]
- fn should_not_parse_non_hidden_attribute() {
- let source = @"#[doc = \"\"]";
- let attrs = parse_attributes(source);
- assert!(parse_hidden(attrs) == false);
- }
-
- #[test]
- fn should_concatenate_multiple_doc_comments() {
- let source = @"/// foo\n/// bar";
- let desc = parse_desc(parse_attributes(source));
- assert!(desc == Some(~" foo\n bar"));
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-The attribute parsing pass
-
-Traverses the document tree, pulling relevant documention out of the
-corresponding AST nodes. The information gathered here is the basis
-of the natural-language documentation for a crate.
-*/
-
-
-use astsrv;
-use attr_parser;
-use doc::ItemUtils;
-use doc;
-use extract::to_str;
-use fold::Fold;
-use fold;
-use pass::Pass;
-
-use syntax::ast;
-use syntax::ast_map;
-
-pub fn mk_pass() -> Pass {
- Pass {
- name: ~"attr",
- f: run
- }
-}
-
-pub fn run(
- srv: astsrv::Srv,
- doc: doc::Doc
-) -> doc::Doc {
- let fold = Fold {
- ctxt: srv.clone(),
- fold_crate: fold_crate,
- fold_item: fold_item,
- fold_enum: fold_enum,
- fold_trait: fold_trait,
- fold_impl: fold_impl,
- .. fold::default_any_fold(srv)
- };
- (fold.fold_doc)(&fold, doc)
-}
-
-fn fold_crate(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::CrateDoc
-) -> doc::CrateDoc {
-
- let srv = fold.ctxt.clone();
- let doc = fold::default_seq_fold_crate(fold, doc);
-
- let attrs = do astsrv::exec(srv) |ctxt| {
- let attrs = ctxt.ast.attrs.clone();
- attr_parser::parse_crate(attrs)
- };
-
- doc::CrateDoc {
- topmod: doc::ModDoc {
- item: doc::ItemDoc {
- name: attrs.name.clone().unwrap_or(doc.topmod.name_()),
- .. doc.topmod.item.clone()
- },
- .. doc.topmod.clone()
- }
- }
-}
-
-fn fold_item(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::ItemDoc
-) -> doc::ItemDoc {
-
- let srv = fold.ctxt.clone();
- let doc = fold::default_seq_fold_item(fold, doc);
-
- let desc = if doc.id == ast::CRATE_NODE_ID {
- // This is the top-level mod, use the crate attributes
- do astsrv::exec(srv) |ctxt| {
- attr_parser::parse_desc(ctxt.ast.attrs.clone())
- }
- } else {
- parse_item_attrs(srv, doc.id, attr_parser::parse_desc)
- };
-
- doc::ItemDoc {
- desc: desc,
- .. doc
- }
-}
-
-fn parse_item_attrs<T:Send>(
- srv: astsrv::Srv,
- id: doc::AstId,
- parse_attrs: ~fn(a: ~[ast::Attribute]) -> T) -> T {
- do astsrv::exec(srv) |ctxt| {
- let attrs = match ctxt.ast_map.get_copy(&id) {
- ast_map::node_item(item, _) => item.attrs.clone(),
- ast_map::node_foreign_item(item, _, _, _) => item.attrs.clone(),
- _ => fail!("parse_item_attrs: not an item")
- };
- parse_attrs(attrs)
- }
-}
-
-fn fold_enum(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::EnumDoc
-) -> doc::EnumDoc {
-
- let srv = fold.ctxt.clone();
- let doc_id = doc.id();
- let doc = fold::default_seq_fold_enum(fold, doc);
-
- doc::EnumDoc {
- variants: do doc.variants.iter().map |variant| {
- let variant = (*variant).clone();
- let desc = {
- let variant = variant.clone();
- do astsrv::exec(srv.clone()) |ctxt| {
- match ctxt.ast_map.get_copy(&doc_id) {
- ast_map::node_item(@ast::item {
- node: ast::item_enum(ref enum_definition, _), _
- }, _) => {
- let ast_variant =
- (*enum_definition.variants.iter().find(|v| {
- to_str(v.node.name) == variant.name
- }).unwrap()).clone();
-
- attr_parser::parse_desc(
- ast_variant.node.attrs.clone())
- }
- _ => {
- fail!("Enum variant %s has id that's not bound to an enum item",
- variant.name)
- }
- }
- }
- };
-
- doc::VariantDoc {
- desc: desc,
- .. variant
- }
- }.collect(),
- .. doc
- }
-}
-
-fn fold_trait(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::TraitDoc
-) -> doc::TraitDoc {
- let srv = fold.ctxt.clone();
- let doc = fold::default_seq_fold_trait(fold, doc);
-
- doc::TraitDoc {
- methods: merge_method_attrs(srv, doc.id(), doc.methods.clone()),
- .. doc
- }
-}
-
-fn merge_method_attrs(
- srv: astsrv::Srv,
- item_id: doc::AstId,
- docs: ~[doc::MethodDoc]
-) -> ~[doc::MethodDoc] {
-
- // Create an assoc list from method name to attributes
- let attrs: ~[(~str, Option<~str>)] = do astsrv::exec(srv) |ctxt| {
- match ctxt.ast_map.get_copy(&item_id) {
- ast_map::node_item(@ast::item {
- node: ast::item_trait(_, _, ref methods), _
- }, _) => {
- methods.iter().map(|method| {
- match (*method).clone() {
- ast::required(ty_m) => {
- (to_str(ty_m.ident),
- attr_parser::parse_desc(ty_m.attrs.clone()))
- }
- ast::provided(m) => {
- (to_str(m.ident), attr_parser::parse_desc(m.attrs.clone()))
- }
- }
- }).collect()
- }
- ast_map::node_item(@ast::item {
- node: ast::item_impl(_, _, _, ref methods), _
- }, _) => {
- methods.iter().map(|method| {
- (to_str(method.ident),
- attr_parser::parse_desc(method.attrs.clone()))
- }).collect()
- }
- _ => fail!("unexpected item")
- }
- };
-
- do docs.iter().zip(attrs.iter()).map |(doc, attrs)| {
- assert!(doc.name == attrs.first());
- let desc = attrs.second();
-
- doc::MethodDoc {
- desc: desc,
- .. (*doc).clone()
- }
- }.collect()
-}
-
-
-fn fold_impl(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::ImplDoc
-) -> doc::ImplDoc {
- let srv = fold.ctxt.clone();
- let doc = fold::default_seq_fold_impl(fold, doc);
-
- doc::ImplDoc {
- methods: merge_method_attrs(srv, doc.id(), doc.methods.clone()),
- .. doc
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use astsrv;
- use attr_pass::run;
- use doc;
- use extract;
-
- fn mk_doc(source: ~str) -> doc::Doc {
- do astsrv::from_str(source.clone()) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- run(srv.clone(), doc)
- }
- }
-
- #[test]
- fn should_replace_top_module_name_with_crate_name() {
- let doc = mk_doc(~"#[link(name = \"bond\")];");
- assert!(doc.cratemod().name_() == ~"bond");
- }
-
- #[test]
- fn should_should_extract_mod_attributes() {
- let doc = mk_doc(~"#[doc = \"test\"] mod a { }");
- // hidden __std_macros module at the start.
- assert!(doc.cratemod().mods()[1].desc() == Some(~"test"));
- }
-
- #[test]
- fn should_extract_top_mod_attributes() {
- let doc = mk_doc(~"#[doc = \"test\"];");
- assert!(doc.cratemod().desc() == Some(~"test"));
- }
-
- #[test]
- fn should_extract_foreign_fn_attributes() {
- let doc = mk_doc(~"extern { #[doc = \"test\"] fn a(); }");
- assert!(doc.cratemod().nmods()[0].fns[0].desc() == Some(~"test"));
- }
-
- #[test]
- fn should_extract_fn_attributes() {
- let doc = mk_doc(~"#[doc = \"test\"] fn a() -> int { }");
- assert!(doc.cratemod().fns()[0].desc() == Some(~"test"));
- }
-
- #[test]
- fn should_extract_enum_docs() {
- let doc = mk_doc(~"#[doc = \"b\"]\
- enum a { v }");
- debug!("%?", doc);
- assert!(doc.cratemod().enums()[0].desc() == Some(~"b"));
- }
-
- #[test]
- fn should_extract_variant_docs() {
- let doc = mk_doc(~"enum a { #[doc = \"c\"] v }");
- assert!(doc.cratemod().enums()[0].variants[0].desc == Some(~"c"));
- }
-
- #[test]
- fn should_extract_trait_docs() {
- let doc = mk_doc(~"#[doc = \"whatever\"] trait i { fn a(); }");
- assert!(doc.cratemod().traits()[0].desc() == Some(~"whatever"));
- }
-
- #[test]
- fn should_extract_trait_method_docs() {
- let doc = mk_doc(
- ~"trait i {\
- #[doc = \"desc\"]\
- fn f(a: bool) -> bool;\
- }");
- assert!(doc.cratemod().traits()[0].methods[0].desc == Some(~"desc"));
- }
-
- #[test]
- fn should_extract_impl_docs() {
- let doc = mk_doc(
- ~"#[doc = \"whatever\"] impl int { fn a() { } }");
- assert!(doc.cratemod().impls()[0].desc() == Some(~"whatever"));
- }
-
- #[test]
- fn should_extract_impl_method_docs() {
- let doc = mk_doc(
- ~"impl int {\
- #[doc = \"desc\"]\
- fn f(a: bool) -> bool { }\
- }");
- assert!(doc.cratemod().impls()[0].methods[0].desc == Some(~"desc"));
- }
-}
--- /dev/null
+// Copyright 2012-2013 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.
+
+//! This module contains the "cleaned" pieces of the AST, and the functions
+//! that clean them.
+
+use its = syntax::parse::token::ident_to_str;
+
+use syntax;
+use syntax::ast;
+use syntax::attr::AttributeMethods;
+
+use std;
+use doctree;
+use visit_ast;
+use std::local_data;
+
+pub trait Clean<T> {
+ fn clean(&self) -> T;
+}
+
+impl<T: Clean<U>, U> Clean<~[U]> for ~[T] {
+ fn clean(&self) -> ~[U] {
+ self.iter().map(|x| x.clean()).collect()
+ }
+}
+impl<T: Clean<U>, U> Clean<U> for @T {
+ fn clean(&self) -> U {
+ (**self).clean()
+ }
+}
+
+impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
+ fn clean(&self) -> Option<U> {
+ match self {
+ &None => None,
+ &Some(ref v) => Some(v.clean())
+ }
+ }
+}
+
+impl<T: Clean<U>, U> Clean<~[U]> for syntax::opt_vec::OptVec<T> {
+ fn clean(&self) -> ~[U] {
+ match self {
+ &syntax::opt_vec::Empty => ~[],
+ &syntax::opt_vec::Vec(ref v) => v.clean()
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Crate {
+ name: ~str,
+ module: Option<Item>,
+}
+
+impl Clean<Crate> for visit_ast::RustdocVisitor {
+ fn clean(&self) -> Crate {
+ use syntax::attr::{find_linkage_metas, last_meta_item_value_str_by_name};
+ let maybe_meta = last_meta_item_value_str_by_name(find_linkage_metas(self.attrs), "name");
+
+ Crate {
+ name: match maybe_meta {
+ Some(x) => x.to_owned(),
+ None => fail!("rustdoc_ng requires a #[link(name=\"foo\")] crate attribute"),
+ },
+ module: Some(self.module.clean()),
+ }
+ }
+}
+
+/// Anything with a source location and set of attributes and, optionally, a
+/// name. That is, anything that can be documented. This doesn't correspond
+/// directly to the AST's concept of an item; it's a strict superset.
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Item {
+ /// Stringified span
+ source: ~str,
+ /// Not everything has a name. E.g., impls
+ name: Option<~str>,
+ attrs: ~[Attribute],
+ inner: ItemEnum,
+ visibility: Option<Visibility>,
+ id: ast::NodeId,
+}
+
+impl Item {
+ /// Finds the `doc` attribute as a List and returns the list of attributes
+ /// nested inside.
+ pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> {
+ for attr in self.attrs.iter() {
+ match *attr {
+ List(~"doc", ref list) => { return Some(list.as_slice()); }
+ _ => {}
+ }
+ }
+ return None;
+ }
+
+ /// Finds the `doc` attribute as a NameValue and returns the corresponding
+ /// value found.
+ pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
+ for attr in self.attrs.iter() {
+ match *attr {
+ NameValue(~"doc", ref v) => { return Some(v.as_slice()); }
+ _ => {}
+ }
+ }
+ return None;
+ }
+
+ pub fn is_mod(&self) -> bool {
+ match self.inner { ModuleItem(*) => true, _ => false }
+ }
+ pub fn is_trait(&self) -> bool {
+ match self.inner { TraitItem(*) => true, _ => false }
+ }
+ pub fn is_struct(&self) -> bool {
+ match self.inner { StructItem(*) => true, _ => false }
+ }
+ pub fn is_enum(&self) -> bool {
+ match self.inner { EnumItem(*) => true, _ => false }
+ }
+ pub fn is_fn(&self) -> bool {
+ match self.inner { FunctionItem(*) => true, _ => false }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub enum ItemEnum {
+ StructItem(Struct),
+ EnumItem(Enum),
+ FunctionItem(Function),
+ ModuleItem(Module),
+ TypedefItem(Typedef),
+ StaticItem(Static),
+ TraitItem(Trait),
+ ImplItem(Impl),
+ ViewItemItem(ViewItem),
+ TyMethodItem(TyMethod),
+ MethodItem(Method),
+ StructFieldItem(StructField),
+ VariantItem(Variant),
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Module {
+ items: ~[Item],
+}
+
+impl Clean<Item> for doctree::Module {
+ fn clean(&self) -> Item {
+ let name = if self.name.is_some() {
+ self.name.unwrap().clean()
+ } else {
+ ~""
+ };
+ Item {
+ name: Some(name),
+ attrs: self.attrs.clean(),
+ source: self.where.clean(),
+ visibility: self.vis.clean(),
+ id: self.id,
+ inner: ModuleItem(Module {
+ items: std::vec::concat(&[self.structs.clean(),
+ self.enums.clean(), self.fns.clean(),
+ self.mods.clean(), self.typedefs.clean(),
+ self.statics.clean(), self.traits.clean(),
+ self.impls.clean(), self.view_items.clean()])
+ })
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub enum Attribute {
+ Word(~str),
+ List(~str, ~[Attribute]),
+ NameValue(~str, ~str)
+}
+
+impl Clean<Attribute> for ast::MetaItem {
+ fn clean(&self) -> Attribute {
+ match self.node {
+ ast::MetaWord(s) => Word(s.to_owned()),
+ ast::MetaList(ref s, ref l) => List(s.to_owned(), l.clean()),
+ ast::MetaNameValue(s, ref v) => NameValue(s.to_owned(), lit_to_str(v))
+ }
+ }
+}
+
+impl Clean<Attribute> for ast::Attribute {
+ fn clean(&self) -> Attribute {
+ self.desugar_doc().node.value.clean()
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct TyParam {
+ name: ~str,
+ id: ast::NodeId,
+ bounds: ~[TyParamBound]
+}
+
+impl Clean<TyParam> for ast::TyParam {
+ fn clean(&self) -> TyParam {
+ TyParam {
+ name: self.ident.clean(),
+ id: self.id,
+ bounds: self.bounds.clean(),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub enum TyParamBound {
+ RegionBound,
+ TraitBound(Type)
+}
+
+impl Clean<TyParamBound> for ast::TyParamBound {
+ fn clean(&self) -> TyParamBound {
+ match *self {
+ ast::RegionTyParamBound => RegionBound,
+ ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Lifetime(~str);
+
+impl Clean<Lifetime> for ast::Lifetime {
+ fn clean(&self) -> Lifetime {
+ Lifetime(self.ident.clean())
+ }
+}
+
+// maybe use a Generic enum and use ~[Generic]?
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Generics {
+ lifetimes: ~[Lifetime],
+ type_params: ~[TyParam]
+}
+
+impl Generics {
+ fn new() -> Generics {
+ Generics {
+ lifetimes: ~[],
+ type_params: ~[]
+ }
+ }
+}
+
+impl Clean<Generics> for ast::Generics {
+ fn clean(&self) -> Generics {
+ Generics {
+ lifetimes: self.lifetimes.clean(),
+ type_params: self.ty_params.clean(),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Method {
+ generics: Generics,
+ self_: SelfTy,
+ purity: ast::purity,
+ decl: FnDecl,
+}
+
+impl Clean<Item> for ast::method {
+ fn clean(&self) -> Item {
+ Item {
+ name: Some(self.ident.clean()),
+ attrs: self.attrs.clean(),
+ source: self.span.clean(),
+ id: self.self_id.clone(),
+ visibility: None,
+ inner: MethodItem(Method {
+ generics: self.generics.clean(),
+ self_: self.explicit_self.clean(),
+ purity: self.purity.clone(),
+ decl: self.decl.clean(),
+ }),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct TyMethod {
+ purity: ast::purity,
+ decl: FnDecl,
+ generics: Generics,
+ self_: SelfTy,
+}
+
+impl Clean<Item> for ast::TypeMethod {
+ fn clean(&self) -> Item {
+ Item {
+ name: Some(self.ident.clean()),
+ attrs: self.attrs.clean(),
+ source: self.span.clean(),
+ id: self.id,
+ visibility: None,
+ inner: TyMethodItem(TyMethod {
+ purity: self.purity.clone(),
+ decl: self.decl.clean(),
+ self_: self.explicit_self.clean(),
+ generics: self.generics.clean(),
+ }),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub enum SelfTy {
+ SelfStatic,
+ SelfValue,
+ SelfBorrowed(Option<Lifetime>, Mutability),
+ SelfManaged(Mutability),
+ SelfOwned,
+}
+
+impl Clean<SelfTy> for ast::explicit_self {
+ fn clean(&self) -> SelfTy {
+ match self.node {
+ ast::sty_static => SelfStatic,
+ ast::sty_value => SelfValue,
+ ast::sty_uniq => SelfOwned,
+ ast::sty_region(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()),
+ ast::sty_box(mt) => SelfManaged(mt.clean()),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Function {
+ decl: FnDecl,
+ generics: Generics,
+}
+
+impl Clean<Item> for doctree::Function {
+ fn clean(&self) -> Item {
+ Item {
+ name: Some(self.name.clean()),
+ attrs: self.attrs.clean(),
+ source: self.where.clean(),
+ visibility: self.vis.clean(),
+ id: self.id,
+ inner: FunctionItem(Function {
+ decl: self.decl.clean(),
+ generics: self.generics.clean(),
+ }),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct ClosureDecl {
+ sigil: ast::Sigil,
+ region: Option<Lifetime>,
+ lifetimes: ~[Lifetime],
+ decl: FnDecl,
+ onceness: ast::Onceness,
+ purity: ast::purity,
+ bounds: ~[TyParamBound]
+}
+
+impl Clean<ClosureDecl> for ast::TyClosure {
+ fn clean(&self) -> ClosureDecl {
+ ClosureDecl {
+ sigil: self.sigil,
+ region: self.region.clean(),
+ lifetimes: self.lifetimes.clean(),
+ decl: self.decl.clean(),
+ onceness: self.onceness,
+ purity: self.purity,
+ bounds: match self.bounds {
+ Some(ref x) => x.clean(),
+ None => ~[]
+ },
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct FnDecl {
+ inputs: ~[Argument],
+ output: Type,
+ cf: RetStyle,
+ attrs: ~[Attribute]
+}
+
+impl Clean<FnDecl> for ast::fn_decl {
+ fn clean(&self) -> FnDecl {
+ FnDecl {
+ inputs: self.inputs.iter().map(|x| x.clean()).collect(),
+ output: (self.output.clean()),
+ cf: self.cf.clean(),
+ attrs: ~[]
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Argument {
+ type_: Type,
+ name: ~str,
+ id: ast::NodeId
+}
+
+impl Clean<Argument> for ast::arg {
+ fn clean(&self) -> Argument {
+ Argument {
+ name: name_from_pat(self.pat),
+ type_: (self.ty.clean()),
+ id: self.id
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub enum RetStyle {
+ NoReturn,
+ Return
+}
+
+impl Clean<RetStyle> for ast::ret_style {
+ fn clean(&self) -> RetStyle {
+ match *self {
+ ast::return_val => Return,
+ ast::noreturn => NoReturn
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Trait {
+ methods: ~[TraitMethod],
+ generics: Generics,
+ parents: ~[Type],
+}
+
+impl Clean<Item> for doctree::Trait {
+ fn clean(&self) -> Item {
+ Item {
+ name: Some(self.name.clean()),
+ attrs: self.attrs.clean(),
+ source: self.where.clean(),
+ id: self.id,
+ visibility: self.vis.clean(),
+ inner: TraitItem(Trait {
+ methods: self.methods.clean(),
+ generics: self.generics.clean(),
+ parents: self.parents.clean(),
+ }),
+ }
+ }
+}
+
+impl Clean<Type> for ast::trait_ref {
+ fn clean(&self) -> Type {
+ let t = Unresolved(self.path.clean(), None, self.ref_id);
+ resolve_type(&t)
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub enum TraitMethod {
+ Required(Item),
+ Provided(Item),
+}
+
+impl TraitMethod {
+ pub fn is_req(&self) -> bool {
+ match self {
+ &Required(*) => true,
+ _ => false,
+ }
+ }
+ pub fn is_def(&self) -> bool {
+ match self {
+ &Provided(*) => true,
+ _ => false,
+ }
+ }
+ pub fn item<'a>(&'a self) -> &'a Item {
+ match *self {
+ Required(ref item) => item,
+ Provided(ref item) => item,
+ }
+ }
+}
+
+impl Clean<TraitMethod> for ast::trait_method {
+ fn clean(&self) -> TraitMethod {
+ match self {
+ &ast::required(ref t) => Required(t.clean()),
+ &ast::provided(ref t) => Provided(t.clean()),
+ }
+ }
+}
+
+/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
+/// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
+/// it does not preserve mutability or boxes.
+#[deriving(Clone, Encodable, Decodable)]
+pub enum Type {
+ /// Most types start out as "Unresolved". It serves as an intermediate stage between cleaning
+ /// and type resolution.
+ Unresolved(Path, Option<~[TyParamBound]>, ast::NodeId),
+ /// structs/enums/traits (anything that'd be an ast::ty_path)
+ ResolvedPath { path: Path, typarams: Option<~[TyParamBound]>, id: ast::NodeId },
+ /// Reference to an item in an external crate (fully qualified path)
+ External(~str, ~str),
+ // I have no idea how to usefully use this.
+ TyParamBinder(ast::NodeId),
+ /// For parameterized types, so the consumer of the JSON don't go looking
+ /// for types which don't exist anywhere.
+ Generic(ast::NodeId),
+ /// For references to self
+ Self(ast::NodeId),
+ /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
+ Primitive(ast::prim_ty),
+ Closure(~ClosureDecl),
+ /// extern "ABI" fn
+ BareFunction(~BareFunctionDecl),
+ Tuple(~[Type]),
+ Vector(~Type),
+ FixedVector(~Type, ~str),
+ String,
+ Bool,
+ /// aka ty_nil
+ Unit,
+ /// aka ty_bot
+ Bottom,
+ Unique(~Type),
+ Managed(Mutability, ~Type),
+ RawPointer(Mutability, ~Type),
+ BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: ~Type},
+ // region, raw, other boxes, mutable
+}
+
+impl Clean<Type> for ast::Ty {
+ fn clean(&self) -> Type {
+ use syntax::ast::*;
+ debug!("cleaning type `%?`", self);
+ let codemap = local_data::get(super::ctxtkey, |x| *x.unwrap()).sess.codemap;
+ debug!("span corresponds to `%s`", codemap.span_to_str(self.span));
+ let t = match self.node {
+ ty_nil => Unit,
+ ty_ptr(ref m) => RawPointer(m.mutbl.clean(), ~resolve_type(&m.ty.clean())),
+ ty_rptr(ref l, ref m) =>
+ BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(),
+ type_: ~resolve_type(&m.ty.clean())},
+ ty_box(ref m) => Managed(m.mutbl.clean(), ~resolve_type(&m.ty.clean())),
+ ty_uniq(ref m) => Unique(~resolve_type(&m.ty.clean())),
+ ty_vec(ref m) => Vector(~resolve_type(&m.ty.clean())),
+ ty_fixed_length_vec(ref m, ref e) => FixedVector(~resolve_type(&m.ty.clean()),
+ e.span.to_src()),
+ ty_tup(ref tys) => Tuple(tys.iter().map(|x| resolve_type(&x.clean())).collect()),
+ ty_path(ref p, ref tpbs, id) => Unresolved(p.clean(), tpbs.clean(), id),
+ ty_closure(ref c) => Closure(~c.clean()),
+ ty_bare_fn(ref barefn) => BareFunction(~barefn.clean()),
+ ty_bot => Bottom,
+ ref x => fail!("Unimplemented type %?", x),
+ };
+ resolve_type(&t)
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct StructField {
+ type_: Type,
+}
+
+impl Clean<Item> for ast::struct_field {
+ fn clean(&self) -> Item {
+ let (name, vis) = match self.node.kind {
+ ast::named_field(id, vis) => (Some(id), Some(vis)),
+ _ => (None, None)
+ };
+ Item {
+ name: name.clean(),
+ attrs: self.node.attrs.clean(),
+ source: self.span.clean(),
+ visibility: vis,
+ id: self.node.id,
+ inner: StructFieldItem(StructField {
+ type_: self.node.ty.clean(),
+ }),
+ }
+ }
+}
+
+pub type Visibility = ast::visibility;
+
+impl Clean<Option<Visibility>> for ast::visibility {
+ fn clean(&self) -> Option<Visibility> {
+ Some(*self)
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Struct {
+ struct_type: doctree::StructType,
+ generics: Generics,
+ fields: ~[Item],
+}
+
+impl Clean<Item> for doctree::Struct {
+ fn clean(&self) -> Item {
+ Item {
+ name: Some(self.name.clean()),
+ attrs: self.attrs.clean(),
+ source: self.where.clean(),
+ id: self.id,
+ visibility: self.vis.clean(),
+ inner: StructItem(Struct {
+ struct_type: self.struct_type,
+ generics: self.generics.clean(),
+ fields: self.fields.clean(),
+ }),
+ }
+ }
+}
+
+/// This is a more limited form of the standard Struct, different in that it
+/// it lacks the things most items have (name, id, parameterization). Found
+/// only as a variant in an enum.
+#[deriving(Clone, Encodable, Decodable)]
+pub struct VariantStruct {
+ struct_type: doctree::StructType,
+ fields: ~[Item],
+}
+
+impl Clean<VariantStruct> for syntax::ast::struct_def {
+ fn clean(&self) -> VariantStruct {
+ VariantStruct {
+ struct_type: doctree::struct_type_from_def(self),
+ fields: self.fields.clean(),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Enum {
+ variants: ~[Item],
+ generics: Generics,
+}
+
+impl Clean<Item> for doctree::Enum {
+ fn clean(&self) -> Item {
+ Item {
+ name: Some(self.name.clean()),
+ attrs: self.attrs.clean(),
+ source: self.where.clean(),
+ id: self.id,
+ visibility: self.vis.clean(),
+ inner: EnumItem(Enum {
+ variants: self.variants.clean(),
+ generics: self.generics.clean(),
+ }),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Variant {
+ kind: VariantKind,
+}
+
+impl Clean<Item> for doctree::Variant {
+ fn clean(&self) -> Item {
+ Item {
+ name: Some(self.name.clean()),
+ attrs: self.attrs.clean(),
+ source: self.where.clean(),
+ visibility: self.vis.clean(),
+ id: self.id,
+ inner: VariantItem(Variant {
+ kind: self.kind.clean(),
+ }),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub enum VariantKind {
+ CLikeVariant,
+ TupleVariant(~[Type]),
+ StructVariant(VariantStruct),
+}
+
+impl Clean<VariantKind> for ast::variant_kind {
+ fn clean(&self) -> VariantKind {
+ match self {
+ &ast::tuple_variant_kind(ref args) => {
+ if args.len() == 0 {
+ CLikeVariant
+ } else {
+ TupleVariant(args.iter().map(|x| x.ty.clean()).collect())
+ }
+ },
+ &ast::struct_variant_kind(ref sd) => StructVariant(sd.clean()),
+ }
+ }
+}
+
+impl Clean<~str> for syntax::codemap::Span {
+ fn clean(&self) -> ~str {
+ let cm = local_data::get(super::ctxtkey, |x| x.unwrap().clone()).sess.codemap;
+ cm.span_to_str(*self)
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Path {
+ global: bool,
+ segments: ~[PathSegment],
+}
+
+impl Clean<Path> for ast::Path {
+ fn clean(&self) -> Path {
+ Path {
+ global: self.global,
+ segments: self.segments.clean()
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct PathSegment {
+ name: ~str,
+ lifetime: Option<Lifetime>,
+ types: ~[Type],
+}
+
+impl Clean<PathSegment> for ast::PathSegment {
+ fn clean(&self) -> PathSegment {
+ PathSegment {
+ name: self.identifier.clean(),
+ lifetime: self.lifetime.clean(),
+ types: self.types.clean()
+ }
+ }
+}
+
+fn path_to_str(p: &ast::Path) -> ~str {
+ use syntax::parse::token::interner_get;
+
+ let mut s = ~"";
+ let mut first = true;
+ for i in p.segments.iter().map(|x| interner_get(x.identifier.name)) {
+ if !first || p.global {
+ s.push_str("::");
+ } else {
+ first = false;
+ }
+ s.push_str(i);
+ }
+ s
+}
+
+impl Clean<~str> for ast::Ident {
+ fn clean(&self) -> ~str {
+ its(self).to_owned()
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Typedef {
+ type_: Type,
+ generics: Generics,
+}
+
+impl Clean<Item> for doctree::Typedef {
+ fn clean(&self) -> Item {
+ Item {
+ name: Some(self.name.clean()),
+ attrs: self.attrs.clean(),
+ source: self.where.clean(),
+ id: self.id.clone(),
+ visibility: self.vis.clean(),
+ inner: TypedefItem(Typedef {
+ type_: self.ty.clean(),
+ generics: self.gen.clean(),
+ }),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct BareFunctionDecl {
+ purity: ast::purity,
+ generics: Generics,
+ decl: FnDecl,
+ abi: ~str
+}
+
+impl Clean<BareFunctionDecl> for ast::TyBareFn {
+ fn clean(&self) -> BareFunctionDecl {
+ BareFunctionDecl {
+ purity: self.purity,
+ generics: Generics {
+ lifetimes: self.lifetimes.clean(),
+ type_params: ~[],
+ },
+ decl: self.decl.clean(),
+ abi: self.abis.to_str(),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Static {
+ type_: Type,
+ mutability: Mutability,
+ /// It's useful to have the value of a static documented, but I have no
+ /// desire to represent expressions (that'd basically be all of the AST,
+ /// which is huge!). So, have a string.
+ expr: ~str,
+}
+
+impl Clean<Item> for doctree::Static {
+ fn clean(&self) -> Item {
+ debug!("claning static %s: %?", self.name.clean(), self);
+ Item {
+ name: Some(self.name.clean()),
+ attrs: self.attrs.clean(),
+ source: self.where.clean(),
+ id: self.id,
+ visibility: self.vis.clean(),
+ inner: StaticItem(Static {
+ type_: self.type_.clean(),
+ mutability: self.mutability.clean(),
+ expr: self.expr.span.to_src(),
+ }),
+ }
+ }
+}
+
+#[deriving(ToStr, Clone, Encodable, Decodable)]
+pub enum Mutability {
+ Mutable,
+ Immutable,
+}
+
+impl Clean<Mutability> for ast::Mutability {
+ fn clean(&self) -> Mutability {
+ match self {
+ &ast::MutMutable => Mutable,
+ &ast::MutImmutable => Immutable,
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Impl {
+ generics: Generics,
+ trait_: Option<Type>,
+ for_: Type,
+ methods: ~[Item],
+}
+
+impl Clean<Item> for doctree::Impl {
+ fn clean(&self) -> Item {
+ Item {
+ name: None,
+ attrs: self.attrs.clean(),
+ source: self.where.clean(),
+ id: self.id,
+ visibility: self.vis.clean(),
+ inner: ImplItem(Impl {
+ generics: self.generics.clean(),
+ trait_: self.trait_.clean(),
+ for_: self.for_.clean(),
+ methods: self.methods.clean(),
+ }),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct ViewItem {
+ inner: ViewItemInner
+}
+
+impl Clean<Item> for ast::view_item {
+ fn clean(&self) -> Item {
+ Item {
+ name: None,
+ attrs: self.attrs.clean(),
+ source: self.span.clean(),
+ id: 0,
+ visibility: self.vis.clean(),
+ inner: ViewItemItem(ViewItem {
+ inner: self.node.clean()
+ }),
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub enum ViewItemInner {
+ ExternMod(~str, Option<~str>, ~[Attribute], ast::NodeId),
+ Import(~[ViewPath])
+}
+
+impl Clean<ViewItemInner> for ast::view_item_ {
+ fn clean(&self) -> ViewItemInner {
+ match self {
+ &ast::view_item_extern_mod(ref i, ref p, ref mi, ref id) =>
+ ExternMod(i.clean(), p.map(|x| x.to_owned()), mi.clean(), *id),
+ &ast::view_item_use(ref vp) => Import(vp.clean())
+ }
+ }
+}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub enum ViewPath {
+ SimpleImport(~str, Path, ast::NodeId),
+ GlobImport(Path, ast::NodeId),
+ ImportList(Path, ~[ViewListIdent], ast::NodeId)
+}
+
+impl Clean<ViewPath> for ast::view_path {
+ fn clean(&self) -> ViewPath {
+ match self.node {
+ ast::view_path_simple(ref i, ref p, ref id) => SimpleImport(i.clean(), p.clean(), *id),
+ ast::view_path_glob(ref p, ref id) => GlobImport(p.clean(), *id),
+ ast::view_path_list(ref p, ref pl, ref id) => ImportList(p.clean(), pl.clean(), *id),
+ }
+ }
+}
+
+pub type ViewListIdent = ~str;
+
+impl Clean<ViewListIdent> for ast::path_list_ident {
+ fn clean(&self) -> ViewListIdent {
+ self.node.name.clean()
+ }
+}
+
+// Utilities
+
+trait ToSource {
+ fn to_src(&self) -> ~str;
+}
+
+impl ToSource for syntax::codemap::Span {
+ fn to_src(&self) -> ~str {
+ debug!("converting span %s to snippet", self.clean());
+ let cm = local_data::get(super::ctxtkey, |x| x.unwrap().clone()).sess.codemap.clone();
+ let sn = match cm.span_to_snippet(*self) {
+ Some(x) => x,
+ None => ~""
+ };
+ debug!("got snippet %s", sn);
+ sn
+ }
+}
+
+fn lit_to_str(lit: &ast::lit) -> ~str {
+ match lit.node {
+ ast::lit_str(st) => st.to_owned(),
+ ast::lit_char(c) => ~"'" + std::char::from_u32(c).unwrap().to_str() + "'",
+ ast::lit_int(i, _t) => i.to_str(),
+ ast::lit_uint(u, _t) => u.to_str(),
+ ast::lit_int_unsuffixed(i) => i.to_str(),
+ ast::lit_float(f, _t) => f.to_str(),
+ ast::lit_float_unsuffixed(f) => f.to_str(),
+ ast::lit_bool(b) => b.to_str(),
+ ast::lit_nil => ~"",
+ }
+}
+
+fn name_from_pat(p: &ast::Pat) -> ~str {
+ use syntax::ast::*;
+ match p.node {
+ PatWild => ~"_",
+ PatIdent(_, ref p, _) => path_to_str(p),
+ PatEnum(ref p, _) => path_to_str(p),
+ PatStruct(*) => fail!("tried to get argument name from pat_struct, \
+ which is not allowed in function arguments"),
+ PatTup(*) => ~"(tuple arg NYI)",
+ PatBox(p) => name_from_pat(p),
+ PatUniq(p) => name_from_pat(p),
+ PatRegion(p) => name_from_pat(p),
+ PatLit(*) => fail!("tried to get argument name from pat_lit, \
+ which is not allowed in function arguments"),
+ PatRange(*) => fail!("tried to get argument name from pat_range, \
+ which is not allowed in function arguments"),
+ PatVec(*) => fail!("tried to get argument name from pat_vec, \
+ which is not allowed in function arguments")
+ }
+}
+
+fn remove_comment_tags(s: &str) -> ~str {
+ if s.starts_with("/") {
+ match s.slice(0,3) {
+ &"///" => return s.slice(3, s.len()).trim().to_owned(),
+ &"/**" | &"/*!" => return s.slice(3, s.len() - 2).trim().to_owned(),
+ _ => return s.trim().to_owned()
+ }
+ } else {
+ return s.to_owned();
+ }
+}
+
+/// Given a Type, resolve it using the def_map
+fn resolve_type(t: &Type) -> Type {
+ use syntax::ast::*;
+
+ let (path, tpbs, id) = match t {
+ &Unresolved(ref path, ref tbps, id) => (path, tbps, id),
+ _ => return (*t).clone(),
+ };
+
+ let dm = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.def_map;
+ debug!("searching for %? in defmap", id);
+ let d = match dm.find(&id) {
+ Some(k) => k,
+ None => {
+ let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap());
+ debug!("could not find %? in defmap (`%s`)", id,
+ syntax::ast_map::node_id_to_str(ctxt.tycx.items, id, ctxt.sess.intr()));
+ fail!("Unexpected failure: unresolved id not in defmap (this is a bug!)")
+ }
+ };
+
+ let def_id = match *d {
+ DefFn(i, _) => i,
+ DefSelf(i) | DefSelfTy(i) => return Self(i),
+ DefTy(i) => i,
+ DefTrait(i) => {
+ debug!("saw DefTrait in def_to_id");
+ i
+ },
+ DefPrimTy(p) => match p {
+ ty_str => return String,
+ ty_bool => return Bool,
+ _ => return Primitive(p)
+ },
+ DefTyParam(i, _) => return Generic(i.node),
+ DefStruct(i) => i,
+ DefTyParamBinder(i) => {
+ debug!("found a typaram_binder, what is it? %d", i);
+ return TyParamBinder(i);
+ },
+ x => fail!("resolved type maps to a weird def %?", x),
+ };
+
+ if def_id.crate != ast::CRATE_NODE_ID {
+ use rustc::metadata::decoder::*;
+
+ let sess = local_data::get(super::ctxtkey, |x| *x.unwrap()).sess;
+ let cratedata = ::rustc::metadata::cstore::get_crate_data(sess.cstore, def_id.crate);
+ let doc = lookup_item(def_id.node, cratedata.data);
+ let path = syntax::ast_map::path_to_str_with_sep(item_path(doc), "::", sess.intr());
+ let ty = match def_like_to_def(item_to_def_like(doc, def_id, def_id.crate)) {
+ DefFn(*) => ~"fn",
+ DefTy(*) => ~"enum",
+ DefTrait(*) => ~"trait",
+ DefPrimTy(p) => match p {
+ ty_str => ~"str",
+ ty_bool => ~"bool",
+ ty_int(t) => match t.to_str() {
+ ~"" => ~"i",
+ s => s
+ },
+ ty_uint(t) => t.to_str(),
+ ty_float(t) => t.to_str(),
+ ty_char => ~"char",
+ },
+ DefTyParam(*) => ~"generic",
+ DefStruct(*) => ~"struct",
+ DefTyParamBinder(*) => ~"typaram_binder",
+ x => fail!("resolved external maps to a weird def %?", x),
+ };
+ let cname = cratedata.name.to_owned();
+ External(cname + "::" + path, ty)
+ } else {
+ ResolvedPath {path: path.clone(), typarams: tpbs.clone(), id: def_id.node}
+ }
+}
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-use std::cell::Cell;
-use std::os;
-use std::result::Result;
-use std::result;
-use std::run::ProcessOutput;
-use std::run;
-use std::vec;
-use extra::getopts;
-
-/// The type of document to output
-#[deriving(Clone, Eq)]
-pub enum OutputFormat {
- /// Markdown
- Markdown,
- /// HTML, via markdown and pandoc
- PandocHtml
-}
-
-/// How to organize the output
-#[deriving(Clone, Eq)]
-pub enum OutputStyle {
- /// All in a single document
- DocPerCrate,
- /// Each module in its own document
- DocPerMod
-}
-
-/// The configuration for a rustdoc session
-#[deriving(Clone)]
-pub struct Config {
- input_crate: Path,
- output_dir: Path,
- output_format: OutputFormat,
- output_style: OutputStyle,
- pandoc_cmd: Option<~str>
-}
-
-fn opt_output_dir() -> ~str { ~"output-dir" }
-fn opt_output_format() -> ~str { ~"output-format" }
-fn opt_output_style() -> ~str { ~"output-style" }
-fn opt_pandoc_cmd() -> ~str { ~"pandoc-cmd" }
-fn opt_help() -> ~str { ~"h" }
-
-fn opts() -> ~[(getopts::Opt, ~str)] {
- ~[
- (getopts::optopt(opt_output_dir()),
- ~"--output-dir <val> Put documents here (default: .)"),
- (getopts::optopt(opt_output_format()),
- ~"--output-format <val> 'markdown' or 'html' (default)"),
- (getopts::optopt(opt_output_style()),
- ~"--output-style <val> 'doc-per-crate' or 'doc-per-mod' (default)"),
- (getopts::optopt(opt_pandoc_cmd()),
- ~"--pandoc-cmd <val> Command for running pandoc"),
- (getopts::optflag(opt_help()),
- ~"-h, --help Print help")
- ]
-}
-
-pub fn usage() {
- use std::io::println;
-
- println("Usage: rustdoc [options] <cratefile>\n");
- println("Options:\n");
- let r = opts();
- for opt in r.iter() {
- printfln!(" %s", opt.second());
- }
- println("");
-}
-
-pub fn default_config(input_crate: &Path) -> Config {
- Config {
- input_crate: (*input_crate).clone(),
- output_dir: Path("."),
- output_format: PandocHtml,
- output_style: DocPerMod,
- pandoc_cmd: None
- }
-}
-
-type Process = ~fn((&str), (&[~str])) -> ProcessOutput;
-
-pub fn mock_process_output(_prog: &str, _args: &[~str]) -> ProcessOutput {
- ProcessOutput {
- status: 0,
- output: ~[],
- error: ~[]
- }
-}
-
-pub fn process_output(prog: &str, args: &[~str]) -> ProcessOutput {
- run::process_output(prog, args)
-}
-
-pub fn parse_config(args: &[~str]) -> Result<Config, ~str> {
- parse_config_(args, process_output)
-}
-
-pub fn parse_config_(
- args: &[~str],
- process_output: Process
-) -> Result<Config, ~str> {
- let args = args.tail();
- let opts = vec::unzip(opts().move_iter()).first();
- match getopts::getopts(args, opts) {
- Ok(matches) => {
- if matches.free.len() == 1 {
- let input_crate = Path(*matches.free.head());
- config_from_opts(&input_crate, &matches, process_output)
- } else if matches.free.is_empty() {
- Err(~"no crates specified")
- } else {
- Err(~"multiple crates specified")
- }
- }
- Err(f) => {
- Err(f.to_err_msg())
- }
- }
-}
-
-fn config_from_opts(
- input_crate: &Path,
- matches: &getopts::Matches,
- process_output: Process
-) -> Result<Config, ~str> {
-
- let config = default_config(input_crate);
- let result = result::Ok(config);
- let result = do result.and_then |config| {
- let output_dir = matches.opt_str(opt_output_dir());
- let output_dir = output_dir.map_move(|s| Path(s));
- result::Ok(Config {
- output_dir: output_dir.unwrap_or(config.output_dir.clone()),
- .. config
- })
- };
- let result = do result.and_then |config| {
- let output_format = matches.opt_str(opt_output_format());
- do output_format.map_move_default(result::Ok(config.clone())) |output_format| {
- do parse_output_format(output_format).and_then |output_format| {
- result::Ok(Config {
- output_format: output_format,
- .. config.clone()
- })
- }
- }
- };
- let result = do result.and_then |config| {
- let output_style =
- matches.opt_str(opt_output_style());
- do output_style.map_move_default(result::Ok(config.clone())) |output_style| {
- do parse_output_style(output_style).and_then |output_style| {
- result::Ok(Config {
- output_style: output_style,
- .. config.clone()
- })
- }
- }
- };
- let process_output = Cell::new(process_output);
- let result = do result.and_then |config| {
- let pandoc_cmd = matches.opt_str(opt_pandoc_cmd());
- let pandoc_cmd = maybe_find_pandoc(
- &config, pandoc_cmd, process_output.take());
- do pandoc_cmd.and_then |pandoc_cmd| {
- result::Ok(Config {
- pandoc_cmd: pandoc_cmd,
- .. config.clone()
- })
- }
- };
- return result;
-}
-
-fn parse_output_format(output_format: &str) -> Result<OutputFormat, ~str> {
- match output_format.to_str() {
- ~"markdown" => result::Ok(Markdown),
- ~"html" => result::Ok(PandocHtml),
- _ => result::Err(fmt!("unknown output format '%s'", output_format))
- }
-}
-
-fn parse_output_style(output_style: &str) -> Result<OutputStyle, ~str> {
- match output_style.to_str() {
- ~"doc-per-crate" => result::Ok(DocPerCrate),
- ~"doc-per-mod" => result::Ok(DocPerMod),
- _ => result::Err(fmt!("unknown output style '%s'", output_style))
- }
-}
-
-pub fn maybe_find_pandoc(
- config: &Config,
- maybe_pandoc_cmd: Option<~str>,
- process_output: Process
-) -> Result<Option<~str>, ~str> {
- if config.output_format != PandocHtml {
- return result::Ok(maybe_pandoc_cmd);
- }
-
- let possible_pandocs = match maybe_pandoc_cmd {
- Some(pandoc_cmd) => ~[pandoc_cmd],
- None => {
- ~[~"pandoc"] + match os::homedir() {
- Some(dir) => {
- ~[dir.push_rel(&Path(".cabal/bin/pandoc")).to_str()]
- }
- None => ~[]
- }
- }
- };
-
- let pandoc = do possible_pandocs.iter().find |&pandoc| {
- let output = process_output(*pandoc, [~"--version"]);
- debug!("testing pandoc cmd %s: %?", *pandoc, output);
- output.status == 0
- };
-
- match pandoc {
- Some(x) => Ok(Some((*x).clone())), // ugly, shouldn't be doubly wrapped
- None => Err(~"couldn't find pandoc")
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use config::*;
- use std::result;
- use std::run::ProcessOutput;
-
- fn parse_config(args: &[~str]) -> Result<Config, ~str> {
- parse_config_(args, mock_process_output)
- }
-
- #[test]
- fn should_find_pandoc() {
- let config = Config {
- output_format: PandocHtml,
- .. default_config(&Path("test"))
- };
- let mock_process_output: ~fn(&str, &[~str]) -> ProcessOutput = |_, _| {
- ProcessOutput { status: 0, output: "pandoc 1.8.2.1".as_bytes().to_owned(), error: ~[] }
- };
- let result = maybe_find_pandoc(&config, None, mock_process_output);
- assert!(result == result::Ok(Some(~"pandoc")));
- }
-
- #[test]
- fn should_error_with_no_pandoc() {
- let config = Config {
- output_format: PandocHtml,
- .. default_config(&Path("test"))
- };
- let mock_process_output: ~fn(&str, &[~str]) -> ProcessOutput = |_, _| {
- ProcessOutput { status: 1, output: ~[], error: ~[] }
- };
- let result = maybe_find_pandoc(&config, None, mock_process_output);
- assert!(result == result::Err(~"couldn't find pandoc"));
- }
-
- #[test]
- fn should_error_with_no_crates() {
- let config = parse_config([~"rustdoc"]);
- assert!(config.unwrap_err() == ~"no crates specified");
- }
-
- #[test]
- fn should_error_with_multiple_crates() {
- let config =
- parse_config([~"rustdoc", ~"crate1.rc", ~"crate2.rc"]);
- assert!(config.unwrap_err() == ~"multiple crates specified");
- }
-
- #[test]
- fn should_set_output_dir_to_cwd_if_not_provided() {
- let config = parse_config([~"rustdoc", ~"crate.rc"]);
- assert!(config.unwrap().output_dir == Path("."));
- }
-
- #[test]
- fn should_set_output_dir_if_provided() {
- let config = parse_config([
- ~"rustdoc", ~"crate.rc", ~"--output-dir", ~"snuggles"
- ]);
- assert!(config.unwrap().output_dir == Path("snuggles"));
- }
-
- #[test]
- fn should_set_output_format_to_pandoc_html_if_not_provided() {
- let config = parse_config([~"rustdoc", ~"crate.rc"]);
- assert!(config.unwrap().output_format == PandocHtml);
- }
-
- #[test]
- fn should_set_output_format_to_markdown_if_requested() {
- let config = parse_config([
- ~"rustdoc", ~"crate.rc", ~"--output-format", ~"markdown"
- ]);
- assert!(config.unwrap().output_format == Markdown);
- }
-
- #[test]
- fn should_set_output_format_to_pandoc_html_if_requested() {
- let config = parse_config([
- ~"rustdoc", ~"crate.rc", ~"--output-format", ~"html"
- ]);
- assert!(config.unwrap().output_format == PandocHtml);
- }
-
- #[test]
- fn should_error_on_bogus_format() {
- let config = parse_config([
- ~"rustdoc", ~"crate.rc", ~"--output-format", ~"bogus"
- ]);
- assert!(config.unwrap_err() == ~"unknown output format 'bogus'");
- }
-
- #[test]
- fn should_set_output_style_to_doc_per_mod_by_default() {
- let config = parse_config([~"rustdoc", ~"crate.rc"]);
- assert!(config.unwrap().output_style == DocPerMod);
- }
-
- #[test]
- fn should_set_output_style_to_one_doc_if_requested() {
- let config = parse_config([
- ~"rustdoc", ~"crate.rc", ~"--output-style", ~"doc-per-crate"
- ]);
- assert!(config.unwrap().output_style == DocPerCrate);
- }
-
- #[test]
- fn should_set_output_style_to_doc_per_mod_if_requested() {
- let config = parse_config([
- ~"rustdoc", ~"crate.rc", ~"--output-style", ~"doc-per-mod"
- ]);
- assert!(config.unwrap().output_style == DocPerMod);
- }
-
- #[test]
- fn should_error_on_bogus_output_style() {
- let config = parse_config([
- ~"rustdoc", ~"crate.rc", ~"--output-style", ~"bogus"
- ]);
- assert!(config.unwrap_err() == ~"unknown output style 'bogus'");
- }
-
- #[test]
- fn should_set_pandoc_command_if_requested() {
- let config = parse_config([
- ~"rustdoc", ~"crate.rc", ~"--pandoc-cmd", ~"panda-bear-doc"
- ]);
- assert!(config.unwrap().pandoc_cmd == Some(~"panda-bear-doc"));
- }
-
- #[test]
- fn should_set_pandoc_command_when_using_pandoc() {
- let config = parse_config([~"rustdoc", ~"crate.rc"]);
- assert!(config.unwrap().pandoc_cmd == Some(~"pandoc"));
- }
-}
--- /dev/null
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc;
+use rustc::{driver, middle};
+
+use syntax;
+use syntax::parse;
+use syntax::ast;
+
+use std::os;
+use std::local_data;
+
+use visit_ast::RustdocVisitor;
+use clean;
+use clean::Clean;
+
+pub struct DocContext {
+ crate: @ast::Crate,
+ tycx: middle::ty::ctxt,
+ sess: driver::session::Session
+}
+
+/// Parses, resolves, and typechecks the given crate
+fn get_ast_and_resolve(cpath: &Path, libs: ~[Path]) -> DocContext {
+ use syntax::codemap::dummy_spanned;
+ use rustc::driver::driver::*;
+
+ let parsesess = parse::new_parse_sess(None);
+ let input = file_input(cpath.clone());
+
+ let sessopts = @driver::session::options {
+ binary: @"rustdoc",
+ maybe_sysroot: Some(@os::self_exe_path().unwrap().pop()),
+ addl_lib_search_paths: @mut libs,
+ .. (*rustc::driver::session::basic_options()).clone()
+ };
+
+
+ let diagnostic_handler = syntax::diagnostic::mk_handler(None);
+ let span_diagnostic_handler =
+ syntax::diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);
+
+ let sess = driver::driver::build_session_(sessopts, parsesess.cm,
+ syntax::diagnostic::emit,
+ span_diagnostic_handler);
+
+ let mut cfg = build_configuration(sess);
+ cfg.push(@dummy_spanned(ast::MetaWord(@"stage2")));
+
+ let mut crate = phase_1_parse_input(sess, cfg.clone(), &input);
+ crate = phase_2_configure_and_expand(sess, cfg, crate);
+ let analysis = phase_3_run_analysis_passes(sess, crate);
+
+ debug!("crate: %?", crate);
+ DocContext { crate: crate, tycx: analysis.ty_cx, sess: sess }
+}
+
+pub fn run_core (libs: ~[Path], path: &Path) -> clean::Crate {
+ let ctxt = @get_ast_and_resolve(path, libs);
+ debug!("defmap:");
+ for (k, v) in ctxt.tycx.def_map.iter() {
+ debug!("%?: %?", k, v);
+ }
+ local_data::set(super::ctxtkey, ctxt);
+
+ let v = @mut RustdocVisitor::new();
+ v.visit(ctxt.crate);
+
+ v.clean()
+}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// no-reformat
-
-/*!
- * A demonstration module
- *
- * Contains documentation in various forms that rustdoc understands,
- * for testing purposes. It doesn't surve any functional
- * purpose. This here, for instance, is just some filler text.
- *
- * FIXME (#3731): It would be nice if we could run some automated
- * tests on this file
- */
-
-
-/// The base price of a muffin on a non-holiday
-static PRICE_OF_A_MUFFIN: float = 70f;
-
-struct WaitPerson {
- hair_color: ~str
-}
-
-/// The type of things that produce omnomnom
-enum OmNomNomy {
- /// Delicious sugar cookies
- Cookie,
- /// It's pizza
- PizzaPie(~[uint])
-}
-
-fn take_my_order_please(
- _waitperson: WaitPerson,
- _order: ~[OmNomNomy]
-) -> uint {
-
- /*!
- * OMG would you take my order already?
- *
- * # Arguments
- *
- * * _waitperson - The waitperson that you want to bother
- * * _order - The order vector. It should be filled with food
- *
- * # Return
- *
- * The price of the order, including tax
- *
- * Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec
- * molestie nisl. Duis massa risus, pharetra a scelerisque a,
- * molestie eu velit. Donec mattis ligula at ante imperdiet ut
- * dapibus mauris malesuada.
- *
- * Sed gravida nisi a metus elementum sit amet hendrerit dolor
- * bibendum. Aenean sit amet neque massa, sed tempus tortor. Sed ut
- * lobortis enim. Proin a mauris quis nunc fermentum ultrices eget a
- * erat. Mauris in lectus vitae metus sodales auctor. Morbi nunc
- * quam, ultricies at venenatis non, pellentesque ac dui.
- *
- * # Failure
- *
- * This function is full of fail
- */
-
- fail!();
-}
-
-mod fortress_of_solitude {
- /*!
- * Superman's vacation home
- *
- * The fortress of solitude is located in the Arctic and it is
- * cold. What you may not know about the fortress of solitude
- * though is that it contains two separate bowling alleys. One of
- * them features bumper-bowling and is kind of lame.
- *
- * Really, it's pretty cool.
- */
-
-}
-
-mod blade_runner {
- /*!
- * Blade Runner is probably the best movie ever
- *
- * I like that in the world of Blade Runner it is always
- * raining, and that it's always night time. And Aliens
- * was also a really good movie.
- *
- * Alien 3 was crap though.
- */
-}
-
-/**
- * Bored
- *
- * Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec
- * molestie nisl. Duis massa risus, pharetra a scelerisque a,
- * molestie eu velit. Donec mattis ligula at ante imperdiet ut
- * dapibus mauris malesuada. Sed gravida nisi a metus elementum sit
- * amet hendrerit dolor bibendum. Aenean sit amet neque massa, sed
- * tempus tortor. Sed ut lobortis enim. Proin a mauris quis nunc
- * fermentum ultrices eget a erat. Mauris in lectus vitae metus
- * sodales auctor. Morbi nunc quam, ultricies at venenatis non,
- * pellentesque ac dui.
- *
- * Quisque vitae est id eros placerat laoreet sit amet eu
- * nisi. Curabitur suscipit neque porttitor est euismod
- * lacinia. Curabitur non quam vitae ipsum adipiscing
- * condimentum. Mauris ut ante eget metus sollicitudin
- * blandit. Aliquam erat volutpat. Morbi sed nisl mauris. Nulla
- * facilisi. Phasellus at mollis ipsum. Maecenas sed convallis
- * sapien. Nullam in ligula turpis. Pellentesque a neque augue. Sed
- * eget ante feugiat tortor congue auctor ac quis ante. Proin
- * condimentum lacinia tincidunt.
- */
-struct Bored {
- bored: bool,
-}
-
-impl Drop for Bored {
- fn drop(&mut self) { }
-}
-
-/**
- * The Shunned House
- *
- * From even the greatest of horrors irony is seldom absent. Sometimes it
- * enters directly into the composition of the events, while sometimes it
- * relates only to their fortuitous position among persons and
- * places. The latter sort is splendidly exemplified by a case in the
- * ancient city of Providence, where in the late forties Edgar Allan Poe
- * used to sojourn often during his unsuccessful wooing of the gifted
- * poetess, Mrs. Whitman. Poe generally stopped at the Mansion House in
- * Benefit Street--the renamed Golden Ball Inn whose roof has sheltered
- * Washington, Jefferson, and Lafayette--and his favorite walk led
- * northward along the same street to Mrs. Whitman's home and the
- * neighboring hillside churchyard of St. John's, whose hidden expanse of
- * Eighteenth Century gravestones had for him a peculiar fascination.
- */
-trait TheShunnedHouse {
- /**
- * Now the irony is this. In this walk, so many times repeated, the
- * world's greatest master of the terrible and the bizarre was
- * obliged to pass a particular house on the eastern side of the
- * street; a dingy, antiquated structure perched on the abruptly
- * rising side hill, with a great unkempt yard dating from a time
- * when the region was partly open country. It does not appear that
- * he ever wrote or spoke of it, nor is there any evidence that he
- * even noticed it. And yet that house, to the two persons in
- * possession of certain information, equals or outranks in horror
- * the wildest fantasy of the genius who so often passed it
- * unknowingly, and stands starkly leering as a symbol of all that is
- * unutterably hideous.
- *
- * # Arguments
- *
- * * unkempt_yard - A yard dating from a time when the region was partly
- * open country
- */
- fn dingy_house(&self, unkempt_yard: int);
-
- /**
- * The house was--and for that matter still is--of a kind to attract
- * the attention of the curious. Originally a farm or semi-farm
- * building, it followed the average New England colonial lines of
- * the middle Eighteenth Century--the prosperous peaked-roof sort,
- * with two stories and dormerless attic, and with the Georgian
- * doorway and interior panelling dictated by the progress of taste
- * at that time. It faced south, with one gable end buried to the
- * lower windows in the eastward rising hill, and the other exposed
- * to the foundations toward the street. Its construction, over a
- * century and a half ago, had followed the grading and straightening
- * of the road in that especial vicinity; for Benefit Street--at
- * first called Back Street--was laid out as a lane winding amongst
- * the graveyards of the first settlers, and straightened only when
- * the removal of the bodies to the North Burial Ground made it
- * decently possible to cut through the old family plots.
- */
- fn construct(&self) -> bool;
-}
-
-/// Whatever
-impl TheShunnedHouse for OmNomNomy {
- fn dingy_house(&self, _unkempt_yard: int) {
- }
-
- fn construct(&self) -> bool {
- fail!();
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-Pulls a brief description out of a long description.
-
-If the first paragraph of a long description is short enough then it
-is interpreted as the brief description.
-*/
-
-
-use astsrv;
-use doc::ItemUtils;
-use doc;
-use fold::Fold;
-use fold;
-use pass::Pass;
-
-use std::util;
-
-pub fn mk_pass() -> Pass {
- Pass {
- name: ~"desc_to_brief",
- f: run
- }
-}
-
-pub fn run(
- _srv: astsrv::Srv,
- doc: doc::Doc
-) -> doc::Doc {
- let fold = Fold {
- fold_item: fold_item,
- fold_trait: fold_trait,
- fold_impl: fold_impl,
- .. fold::default_any_fold(())
- };
- (fold.fold_doc)(&fold, doc)
-}
-
-fn fold_item(fold: &fold::Fold<()>, doc: doc::ItemDoc) -> doc::ItemDoc {
- let doc = fold::default_seq_fold_item(fold, doc);
-
- doc::ItemDoc {
- brief: extract(doc.desc.clone()),
- .. doc
- }
-}
-
-fn fold_trait(fold: &fold::Fold<()>, doc: doc::TraitDoc) -> doc::TraitDoc {
- let doc =fold::default_seq_fold_trait(fold, doc);
-
- doc::TraitDoc {
- methods: doc.methods.map(|doc| doc::MethodDoc {
- brief: extract(doc.desc.clone()),
- .. (*doc).clone()
- }),
- .. doc
- }
-}
-
-fn fold_impl(fold: &fold::Fold<()>, doc: doc::ImplDoc) -> doc::ImplDoc {
- let doc =fold::default_seq_fold_impl(fold, doc);
-
- doc::ImplDoc {
- methods: doc.methods.map(|doc| doc::MethodDoc {
- brief: extract(doc.desc.clone()),
- .. (*doc).clone()
- }),
- .. doc
- }
-}
-
-pub fn extract(desc: Option<~str>) -> Option<~str> {
- if desc.is_none() {
- return None
- }
-
- parse_desc(desc.clone().unwrap())
-}
-
-fn parse_desc(desc: ~str) -> Option<~str> {
- static MAX_BRIEF_LEN: uint = 120u;
-
- match first_sentence(desc.clone()) {
- Some(first_sentence) => {
- if first_sentence.len() <= MAX_BRIEF_LEN {
- Some(first_sentence)
- } else {
- None
- }
- }
- None => None
- }
-}
-
-fn first_sentence(s: ~str) -> Option<~str> {
- let paras = paragraphs(s);
- if !paras.is_empty() {
- let first_para = paras.head();
- Some(first_sentence_(*first_para).replace("\n", " "))
- } else {
- None
- }
-}
-
-fn first_sentence_(s: &str) -> ~str {
- let mut dotcount = 0;
- // The index of the character following a single dot. This allows
- // Things like [0..1) to appear in the brief description
- let idx = s.find(|ch: char| {
- if ch == '.' {
- dotcount += 1;
- false
- } else if dotcount == 1 {
- true
- } else {
- dotcount = 0;
- false
- }
- });
- match idx {
- Some(idx) if idx > 2u => s.slice(0, idx - 1).to_owned(),
- _ => {
- if s.ends_with(".") {
- s.to_owned()
- } else {
- s.to_owned()
- }
- }
- }
-}
-
-pub fn paragraphs(s: &str) -> ~[~str] {
- let mut whitespace_lines = 0;
- let mut accum = ~"";
- let mut paras = do s.any_line_iter().fold(~[]) |paras, line| {
- let mut res = paras;
-
- if line.is_whitespace() {
- whitespace_lines += 1;
- } else {
- if whitespace_lines > 0 {
- if !accum.is_empty() {
- let v = util::replace(&mut accum, ~"");
- res.push(v);
- }
- }
-
- whitespace_lines = 0;
-
- accum = if accum.is_empty() {
- line.to_owned()
- } else {
- fmt!("%s\n%s", accum, line)
- }
- }
-
- res
- };
-
- if !accum.is_empty() { paras.push(accum); }
- paras
-}
-
-#[cfg(test)]
-mod test {
-
- use astsrv;
- use attr_pass;
- use super::{extract, paragraphs, run};
- use doc;
- use extract;
-
- fn mk_doc(source: ~str) -> doc::Doc {
- do astsrv::from_str(source.clone()) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
- run(srv.clone(), doc)
- }
- }
-
- #[test]
- fn should_promote_desc() {
- let doc = mk_doc(~"#[doc = \"desc\"] mod m { }");
- // hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().mods()[1].brief(), Some(~"desc"));
- }
-
- #[test]
- fn should_promote_trait_method_desc() {
- let doc = mk_doc(~"trait i { #[doc = \"desc\"] fn a(); }");
- assert!(doc.cratemod().traits()[0].methods[0].brief ==
- Some(~"desc"));
- }
-
- #[test]
- fn should_promote_impl_method_desc() {
- let doc = mk_doc(
- ~"impl int { #[doc = \"desc\"] fn a() { } }");
- assert!(doc.cratemod().impls()[0].methods[0].brief == Some(~"desc"));
- }
-
- #[test]
- fn test_paragraphs_1() {
- let paras = paragraphs("1\n\n2");
- assert_eq!(paras, ~[~"1", ~"2"]);
- }
-
- #[test]
- fn test_paragraphs_2() {
- let paras = paragraphs("\n\n1\n1\n\n2\n\n");
- assert_eq!(paras, ~[~"1\n1", ~"2"]);
- }
-
- #[test]
- fn should_promote_short_descs() {
- let desc = Some(~"desc");
- let brief = extract(desc.clone());
- assert_eq!(brief, desc);
- }
-
- #[test]
- fn should_not_promote_long_descs() {
- let desc = Some(~"Warkworth Castle is a ruined medieval building
-in the town of the same name in the English county of Northumberland,
-and the town and castle occupy a loop of the River Coquet, less than a mile
-from England's north-east coast. When the castle was founded is uncertain,
-but traditionally its construction has been ascribed to Prince Henry of
-Scotland in the mid 12th century, although it may have been built by
-King Henry II of England when he took control of England'snorthern
-counties.");
- let brief = extract(desc);
- assert_eq!(brief, None);
- }
-
- #[test]
- fn should_promote_first_sentence() {
- let desc = Some(~"Warkworth Castle is a ruined medieval building
-in the town. of the same name in the English county of Northumberland,
-and the town and castle occupy a loop of the River Coquet, less than a mile
-from England's north-east coast. When the castle was founded is uncertain,
-but traditionally its construction has been ascribed to Prince Henry of
-Scotland in the mid 12th century, although it may have been built by
-King Henry II of England when he took control of England'snorthern
-counties.");
- let brief = extract(desc);
- assert!(brief == Some(
- ~"Warkworth Castle is a ruined medieval building in the town"));
- }
-
- #[test]
- fn should_not_consider_double_period_to_end_sentence() {
- let desc = Some(~"Warkworth..Castle is a ruined medieval building
-in the town. of the same name in the English county of Northumberland,
-and the town and castle occupy a loop of the River Coquet, less than a mile
-from England's north-east coast. When the castle was founded is uncertain,
-but traditionally its construction has been ascribed to Prince Henry of
-Scotland in the mid 12th century, although it may have been built by
-King Henry II of England when he took control of England'snorthern
-counties.");
- let brief = extract(desc);
- assert!(brief == Some(
- ~"Warkworth..Castle is a ruined medieval building in the town"));
- }
-
- #[test]
- fn should_not_consider_triple_period_to_end_sentence() {
- let desc = Some(~"Warkworth... Castle is a ruined medieval building
-in the town. of the same name in the English county of Northumberland,
-and the town and castle occupy a loop of the River Coquet, less than a mile
-from England's north-east coast. When the castle was founded is uncertain,
-but traditionally its construction has been ascribed to Prince Henry of
-Scotland in the mid 12th century, although it may have been built by
-King Henry II of England when he took control of England'snorthern
-counties.");
- let brief = extract(desc);
- assert!(brief == Some(
- ~"Warkworth... Castle is a ruined medieval building in the town"));
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The document model
-
-
-use doc;
-
-pub type AstId = int;
-
-#[deriving(Clone, Eq)]
-pub struct Doc {
- pages: ~[Page]
-}
-
-#[deriving(Clone, Eq)]
-pub enum Page {
- CratePage(CrateDoc),
- ItemPage(ItemTag)
-}
-
-#[deriving(Clone, Eq)]
-pub enum Implementation {
- Required,
- Provided,
-}
-
-/**
- * Most rustdocs can be parsed into 'sections' according to their markdown
- * headers
- */
-#[deriving(Clone, Eq)]
-pub struct Section {
- header: ~str,
- body: ~str
-}
-
-// FIXME (#2596): We currently give topmod the name of the crate. There
-// would probably be fewer special cases if the crate had its own name
-// and topmod's name was the empty string.
-#[deriving(Clone, Eq)]
-pub struct CrateDoc {
- topmod: ModDoc
-}
-
-#[deriving(Clone, Eq)]
-pub enum ItemTag {
- ModTag(ModDoc),
- NmodTag(NmodDoc),
- StaticTag(StaticDoc),
- FnTag(FnDoc),
- EnumTag(EnumDoc),
- TraitTag(TraitDoc),
- ImplTag(ImplDoc),
- TyTag(TyDoc),
- StructTag(StructDoc)
-}
-
-#[deriving(Clone, Eq)]
-pub struct ItemDoc {
- id: AstId,
- name: ~str,
- path: ~[~str],
- brief: Option<~str>,
- desc: Option<~str>,
- sections: ~[Section],
- // Indicates that this node is a reexport of a different item
- reexport: bool
-}
-
-#[deriving(Clone, Eq)]
-pub struct SimpleItemDoc {
- item: ItemDoc,
- sig: Option<~str>
-}
-
-#[deriving(Clone, Eq)]
-pub struct ModDoc {
- item: ItemDoc,
- items: ~[ItemTag],
- index: Option<Index>
-}
-
-#[deriving(Clone, Eq)]
-pub struct NmodDoc {
- item: ItemDoc,
- fns: ~[FnDoc],
- index: Option<Index>
-}
-
-pub type StaticDoc = SimpleItemDoc;
-
-pub type FnDoc = SimpleItemDoc;
-
-#[deriving(Clone, Eq)]
-pub struct EnumDoc {
- item: ItemDoc,
- variants: ~[VariantDoc]
-}
-
-#[deriving(Clone, Eq)]
-pub struct VariantDoc {
- name: ~str,
- desc: Option<~str>,
- sig: Option<~str>
-}
-
-#[deriving(Clone, Eq)]
-pub struct TraitDoc {
- item: ItemDoc,
- methods: ~[MethodDoc]
-}
-
-#[deriving(Clone, Eq)]
-pub struct MethodDoc {
- name: ~str,
- brief: Option<~str>,
- desc: Option<~str>,
- sections: ~[Section],
- sig: Option<~str>,
- implementation: Implementation,
-}
-
-#[deriving(Clone, Eq)]
-pub struct ImplDoc {
- item: ItemDoc,
- bounds_str: Option<~str>,
- trait_types: ~[~str],
- self_ty: Option<~str>,
- methods: ~[MethodDoc]
-}
-
-pub type TyDoc = SimpleItemDoc;
-
-#[deriving(Clone, Eq)]
-pub struct StructDoc {
- item: ItemDoc,
- fields: ~[~str],
- sig: Option<~str>
-}
-
-#[deriving(Clone, Eq)]
-pub struct Index {
- entries: ~[IndexEntry]
-}
-
-/**
- * A single entry in an index
- *
- * Fields:
- *
- * * kind - The type of thing being indexed, e.g. 'Module'
- * * name - The name of the thing
- * * brief - The brief description
- * * link - A format-specific string representing the link target
- */
-#[deriving(Clone, Eq)]
-pub struct IndexEntry {
- kind: ~str,
- name: ~str,
- brief: Option<~str>,
- link: ~str
-}
-
-impl Doc {
- pub fn CrateDoc(&self) -> CrateDoc {
- self.pages.iter().fold(None, |_m, page| {
- match (*page).clone() {
- doc::CratePage(doc) => Some(doc),
- _ => None
- }
- }).unwrap()
- }
-
- pub fn cratemod(&self) -> ModDoc {
- self.CrateDoc().topmod.clone()
- }
-}
-
-macro_rules! filt_mapper {
- ($vec:expr, $pat:pat) => {
- do ($vec).iter().filter_map |thing| {
- match thing {
- &$pat => Some((*x).clone()),
- _ => None
- }
- }.collect()
- }
-}
-
-macro_rules! md {
- ($id:ident) => {
- filt_mapper!(self.items, $id(ref x))
- }
-}
-/// Some helper methods on ModDoc, mostly for testing
-impl ModDoc {
- pub fn mods(&self) -> ~[ModDoc] {
- md!(ModTag)
- }
-
- pub fn nmods(&self) -> ~[NmodDoc] {
- md!(NmodTag)
- }
-
- pub fn fns(&self) -> ~[FnDoc] {
- md!(FnTag)
- }
-
- pub fn statics(&self) -> ~[StaticDoc] {
- md!(StaticTag)
- }
-
- pub fn enums(&self) -> ~[EnumDoc] {
- md!(EnumTag)
- }
-
- pub fn traits(&self) -> ~[TraitDoc] {
- md!(TraitTag)
- }
-
- pub fn impls(&self) -> ~[ImplDoc] {
- md!(ImplTag)
- }
-
- pub fn types(&self) -> ~[TyDoc] {
- md!(TyTag)
- }
-
- pub fn structs(&self) -> ~[StructDoc] {
- md!(StructTag)
- }
-}
-
-macro_rules! pu {
- ($id:ident) => {
- filt_mapper!(*self, ItemPage($id(ref x)))
- }
-}
-
-pub trait PageUtils {
- fn mods(&self) -> ~[ModDoc];
- fn nmods(&self) -> ~[NmodDoc];
- fn fns(&self) -> ~[FnDoc];
- fn statics(&self) -> ~[StaticDoc];
- fn enums(&self) -> ~[EnumDoc];
- fn traits(&self) -> ~[TraitDoc];
- fn impls(&self) -> ~[ImplDoc];
- fn types(&self) -> ~[TyDoc];
-}
-
-impl PageUtils for ~[Page] {
-
- fn mods(&self) -> ~[ModDoc] {
- pu!(ModTag)
- }
-
- fn nmods(&self) -> ~[NmodDoc] {
- pu!(NmodTag)
- }
-
- fn fns(&self) -> ~[FnDoc] {
- pu!(FnTag)
- }
-
- fn statics(&self) -> ~[StaticDoc] {
- pu!(StaticTag)
- }
-
- fn enums(&self) -> ~[EnumDoc] {
- pu!(EnumTag)
- }
-
- fn traits(&self) -> ~[TraitDoc] {
- pu!(TraitTag)
- }
-
- fn impls(&self) -> ~[ImplDoc] {
- pu!(ImplTag)
- }
-
- fn types(&self) -> ~[TyDoc] {
- pu!(TyTag)
- }
-}
-
-pub trait Item {
- fn item(&self) -> ItemDoc;
-}
-
-impl Item for ItemTag {
- fn item(&self) -> ItemDoc {
- match self {
- &doc::ModTag(ref doc) => doc.item.clone(),
- &doc::NmodTag(ref doc) => doc.item.clone(),
- &doc::FnTag(ref doc) => doc.item.clone(),
- &doc::StaticTag(ref doc) => doc.item.clone(),
- &doc::EnumTag(ref doc) => doc.item.clone(),
- &doc::TraitTag(ref doc) => doc.item.clone(),
- &doc::ImplTag(ref doc) => doc.item.clone(),
- &doc::TyTag(ref doc) => doc.item.clone(),
- &doc::StructTag(ref doc) => doc.item.clone(),
- }
- }
-}
-
-impl Item for SimpleItemDoc {
- fn item(&self) -> ItemDoc {
- self.item.clone()
- }
-}
-
-impl Item for ModDoc {
- fn item(&self) -> ItemDoc {
- self.item.clone()
- }
-}
-
-impl Item for NmodDoc {
- fn item(&self) -> ItemDoc {
- self.item.clone()
- }
-}
-
-impl Item for EnumDoc {
- fn item(&self) -> ItemDoc {
- self.item.clone()
- }
-}
-
-impl Item for TraitDoc {
- fn item(&self) -> ItemDoc {
- self.item.clone()
- }
-}
-
-impl Item for ImplDoc {
- fn item(&self) -> ItemDoc {
- self.item.clone()
- }
-}
-
-impl Item for StructDoc {
- fn item(&self) -> ItemDoc {
- self.item.clone()
- }
-}
-
-pub trait ItemUtils {
- fn id(&self) -> AstId;
- /// FIXME #5898: This conflicts with
- /// syntax::attr::AttrMetaMethods.name; This rustdoc seems to be on
- /// the way out so I'm making this one look bad rather than the
- /// new methods in attr.
- fn name_(&self) -> ~str;
- fn path(&self) -> ~[~str];
- fn brief(&self) -> Option<~str>;
- fn desc(&self) -> Option<~str>;
- fn sections(&self) -> ~[Section];
-}
-
-impl<A:Item> ItemUtils for A {
- fn id(&self) -> AstId {
- self.item().id
- }
-
- fn name_(&self) -> ~str {
- self.item().name.clone()
- }
-
- fn path(&self) -> ~[~str] {
- self.item().path.clone()
- }
-
- fn brief(&self) -> Option<~str> {
- self.item().brief.clone()
- }
-
- fn desc(&self) -> Option<~str> {
- self.item().desc.clone()
- }
-
- fn sections(&self) -> ~[Section] {
- self.item().sections.clone()
- }
-}
--- /dev/null
+// Copyright 2012-2013 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.
+
+//! This module is used to store stuff from Rust's AST in a more convenient
+//! manner (and with prettier names) before cleaning.
+
+use syntax;
+use syntax::codemap::Span;
+use syntax::ast;
+use syntax::ast::{Ident, NodeId};
+
+pub struct Module {
+ name: Option<Ident>,
+ attrs: ~[ast::Attribute],
+ where: Span,
+ structs: ~[Struct],
+ enums: ~[Enum],
+ fns: ~[Function],
+ mods: ~[Module],
+ id: NodeId,
+ typedefs: ~[Typedef],
+ statics: ~[Static],
+ traits: ~[Trait],
+ vis: ast::visibility,
+ impls: ~[Impl],
+ view_items: ~[ast::view_item],
+}
+
+impl Module {
+ pub fn new(name: Option<Ident>) -> Module {
+ Module {
+ name : name,
+ id: 0,
+ vis: ast::private,
+ where: syntax::codemap::dummy_sp(),
+ attrs : ~[],
+ structs : ~[],
+ enums : ~[],
+ fns : ~[],
+ mods : ~[],
+ typedefs : ~[],
+ statics : ~[],
+ traits : ~[],
+ impls : ~[],
+ view_items : ~[],
+ }
+ }
+}
+
+#[deriving(ToStr, Clone, Encodable, Decodable)]
+pub enum StructType {
+ /// A normal struct
+ Plain,
+ /// A tuple struct
+ Tuple,
+ /// A newtype struct (tuple struct with one element)
+ Newtype,
+ /// A unit struct
+ Unit
+}
+
+pub enum TypeBound {
+ RegionBound,
+ TraitBound(ast::trait_ref)
+}
+
+pub struct Struct {
+ vis: ast::visibility,
+ id: NodeId,
+ struct_type: StructType,
+ name: Ident,
+ generics: ast::Generics,
+ attrs: ~[ast::Attribute],
+ fields: ~[@ast::struct_field],
+ where: Span,
+}
+
+pub struct Enum {
+ vis: ast::visibility,
+ variants: ~[Variant],
+ generics: ast::Generics,
+ attrs: ~[ast::Attribute],
+ id: NodeId,
+ where: Span,
+ name: Ident,
+}
+
+pub struct Variant {
+ name: Ident,
+ attrs: ~[ast::Attribute],
+ kind: ast::variant_kind,
+ id: ast::NodeId,
+ vis: ast::visibility,
+ where: Span,
+}
+
+pub struct Function {
+ decl: ast::fn_decl,
+ attrs: ~[ast::Attribute],
+ id: NodeId,
+ name: Ident,
+ vis: ast::visibility,
+ where: Span,
+ generics: ast::Generics,
+}
+
+pub struct Typedef {
+ ty: ast::Ty,
+ gen: ast::Generics,
+ name: Ident,
+ id: ast::NodeId,
+ attrs: ~[ast::Attribute],
+ where: Span,
+ vis: ast::visibility,
+}
+
+pub struct Static {
+ type_: ast::Ty,
+ mutability: ast::Mutability,
+ expr: @ast::Expr,
+ name: Ident,
+ attrs: ~[ast::Attribute],
+ vis: ast::visibility,
+ id: ast::NodeId,
+ where: Span,
+}
+
+pub struct Trait {
+ name: Ident,
+ methods: ~[ast::trait_method], //should be TraitMethod
+ generics: ast::Generics,
+ parents: ~[ast::trait_ref],
+ attrs: ~[ast::Attribute],
+ id: ast::NodeId,
+ where: Span,
+ vis: ast::visibility,
+}
+
+pub struct Impl {
+ generics: ast::Generics,
+ trait_: Option<ast::trait_ref>,
+ for_: ast::Ty,
+ methods: ~[@ast::method],
+ attrs: ~[ast::Attribute],
+ where: Span,
+ vis: ast::visibility,
+ id: ast::NodeId,
+}
+
+pub fn struct_type_from_def(sd: &ast::struct_def) -> StructType {
+ if sd.ctor_id.is_some() {
+ // We are in a tuple-struct
+ match sd.fields.len() {
+ 0 => Unit,
+ 1 => Newtype,
+ _ => Tuple
+ }
+ } else {
+ Plain
+ }
+}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Escapes text sequences
-
-use pass::Pass;
-use text_pass;
-
-pub fn mk_pass() -> Pass {
- text_pass::mk_pass(~"escape", escape)
-}
-
-fn escape(s: &str) -> ~str {
- s.replace("\\", "\\\\")
-}
-
-#[test]
-fn should_escape_backslashes() {
- let s = ~"\\n";
- let r = escape(s);
- assert_eq!(r, ~"\\\\n");
-}
+++ /dev/null
-// Copyright 2012-2013 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.
-
-//! Converts the Rust AST to the rustdoc document model
-
-
-use astsrv;
-use doc::ItemUtils;
-use doc;
-
-use syntax::ast;
-use syntax::parse::token::{ident_interner, ident_to_str};
-use syntax::parse::token;
-
-// Hack; rather than thread an interner through everywhere, rely on
-// thread-local data
-// Hack-Becomes-Feature: using thread-local-state everywhere...
-pub fn to_str(id: ast::Ident) -> ~str {
- /* bad */ ident_to_str(&id).to_owned()
-}
-
-// get rid of this pointless function:
-pub fn interner() -> @ident_interner {
- return token::get_ident_interner();
-}
-
-pub fn from_srv(
- srv: astsrv::Srv,
- default_name: ~str
-) -> doc::Doc {
-
- //! Use the AST service to create a document tree
-
- do astsrv::exec(srv) |ctxt| {
- extract(ctxt.ast, default_name.clone())
- }
-}
-
-pub fn extract(
- crate: @ast::Crate,
- default_name: ~str
-) -> doc::Doc {
- doc::Doc {
- pages: ~[
- doc::CratePage(doc::CrateDoc {
- topmod: top_moddoc_from_crate(crate, default_name),
- })
- ]
- }
-}
-
-fn top_moddoc_from_crate(
- crate: @ast::Crate,
- default_name: ~str
-) -> doc::ModDoc {
- moddoc_from_mod(mk_itemdoc(ast::CRATE_NODE_ID, default_name),
- crate.module.clone())
-}
-
-fn mk_itemdoc(id: ast::NodeId, name: ~str) -> doc::ItemDoc {
- doc::ItemDoc {
- id: id,
- name: name,
- path: ~[],
- brief: None,
- desc: None,
- sections: ~[],
- reexport: false
- }
-}
-
-fn moddoc_from_mod(
- itemdoc: doc::ItemDoc,
- module_: ast::_mod
-) -> doc::ModDoc {
- doc::ModDoc {
- item: itemdoc,
- items: do module_.items.iter().filter_map |item| {
- let ItemDoc = mk_itemdoc(item.id, to_str(item.ident));
- match item.node.clone() {
- ast::item_mod(m) => {
- Some(doc::ModTag(
- moddoc_from_mod(ItemDoc, m)
- ))
- }
- ast::item_foreign_mod(nm) => {
- Some(doc::NmodTag(
- nmoddoc_from_mod(ItemDoc, nm)
- ))
- }
- ast::item_fn(*) => {
- Some(doc::FnTag(
- fndoc_from_fn(ItemDoc)
- ))
- }
- ast::item_static(*) => {
- Some(doc::StaticTag(
- staticdoc_from_static(ItemDoc)
- ))
- }
- ast::item_enum(enum_definition, _) => {
- Some(doc::EnumTag(
- enumdoc_from_enum(ItemDoc, enum_definition.variants.clone())
- ))
- }
- ast::item_trait(_, _, methods) => {
- Some(doc::TraitTag(
- traitdoc_from_trait(ItemDoc, methods)
- ))
- }
- ast::item_impl(_, _, _, methods) => {
- Some(doc::ImplTag(
- impldoc_from_impl(ItemDoc, methods)
- ))
- }
- ast::item_ty(_, _) => {
- Some(doc::TyTag(
- tydoc_from_ty(ItemDoc)
- ))
- }
- ast::item_struct(def, _) => {
- Some(doc::StructTag(
- structdoc_from_struct(ItemDoc, def)
- ))
- }
- _ => None
- }
- }.collect(),
- index: None
- }
-}
-
-fn nmoddoc_from_mod(
- itemdoc: doc::ItemDoc,
- module_: ast::foreign_mod
-) -> doc::NmodDoc {
- let mut fns = ~[];
- for item in module_.items.iter() {
- let ItemDoc = mk_itemdoc(item.id, to_str(item.ident));
- match item.node {
- ast::foreign_item_fn(*) => {
- fns.push(fndoc_from_fn(ItemDoc));
- }
- ast::foreign_item_static(*) => {} // XXX: Not implemented.
- }
- }
- doc::NmodDoc {
- item: itemdoc,
- fns: fns,
- index: None
- }
-}
-
-fn fndoc_from_fn(itemdoc: doc::ItemDoc) -> doc::FnDoc {
- doc::SimpleItemDoc {
- item: itemdoc,
- sig: None
- }
-}
-
-fn staticdoc_from_static(itemdoc: doc::ItemDoc) -> doc::StaticDoc {
- doc::SimpleItemDoc {
- item: itemdoc,
- sig: None
- }
-}
-
-fn enumdoc_from_enum(
- itemdoc: doc::ItemDoc,
- variants: ~[ast::variant]
-) -> doc::EnumDoc {
- doc::EnumDoc {
- item: itemdoc,
- variants: variantdocs_from_variants(variants)
- }
-}
-
-fn variantdocs_from_variants(
- variants: ~[ast::variant]
-) -> ~[doc::VariantDoc] {
- variants.iter().map(variantdoc_from_variant).collect()
-}
-
-fn variantdoc_from_variant(variant: &ast::variant) -> doc::VariantDoc {
- doc::VariantDoc {
- name: to_str(variant.node.name),
- desc: None,
- sig: None
- }
-}
-
-fn traitdoc_from_trait(
- itemdoc: doc::ItemDoc,
- methods: ~[ast::trait_method]
-) -> doc::TraitDoc {
- doc::TraitDoc {
- item: itemdoc,
- methods: do methods.iter().map |method| {
- match (*method).clone() {
- ast::required(ty_m) => {
- doc::MethodDoc {
- name: to_str(ty_m.ident),
- brief: None,
- desc: None,
- sections: ~[],
- sig: None,
- implementation: doc::Required,
- }
- }
- ast::provided(m) => {
- doc::MethodDoc {
- name: to_str(m.ident),
- brief: None,
- desc: None,
- sections: ~[],
- sig: None,
- implementation: doc::Provided,
- }
- }
- }
- }.collect()
- }
-}
-
-fn impldoc_from_impl(
- itemdoc: doc::ItemDoc,
- methods: ~[@ast::method]
-) -> doc::ImplDoc {
- doc::ImplDoc {
- item: itemdoc,
- bounds_str: None,
- trait_types: ~[],
- self_ty: None,
- methods: do methods.iter().map |method| {
- doc::MethodDoc {
- name: to_str(method.ident),
- brief: None,
- desc: None,
- sections: ~[],
- sig: None,
- implementation: doc::Provided,
- }
- }.collect()
- }
-}
-
-fn tydoc_from_ty(
- itemdoc: doc::ItemDoc
-) -> doc::TyDoc {
- doc::SimpleItemDoc {
- item: itemdoc,
- sig: None
- }
-}
-
-fn structdoc_from_struct(
- itemdoc: doc::ItemDoc,
- struct_def: @ast::struct_def
-) -> doc::StructDoc {
- doc::StructDoc {
- item: itemdoc,
- fields: do struct_def.fields.map |field| {
- match field.node.kind {
- ast::named_field(ident, _) => to_str(ident),
- ast::unnamed_field => ~"(unnamed)",
- }
- },
- sig: None
- }
-}
-
-#[cfg(test)]
-mod test {
- use astsrv;
- use doc;
- use extract::{extract, from_srv};
- use parse;
-
- fn mk_doc(source: @str) -> doc::Doc {
- let ast = parse::from_str(source);
- debug!("ast=%?", ast);
- extract(ast, ~"")
- }
-
- #[test]
- fn extract_empty_crate() {
- let doc = mk_doc(@"");
- assert!(doc.cratemod().mods().is_empty());
- assert!(doc.cratemod().fns().is_empty());
- }
-
- #[test]
- fn extract_mods() {
- let doc = mk_doc(@"mod a { mod b { } mod c { } }");
- assert!(doc.cratemod().mods()[0].name_() == ~"a");
- assert!(doc.cratemod().mods()[0].mods()[0].name_() == ~"b");
- assert!(doc.cratemod().mods()[0].mods()[1].name_() == ~"c");
- }
-
- #[test]
- fn extract_fns_from_foreign_mods() {
- let doc = mk_doc(@"extern { fn a(); }");
- assert!(doc.cratemod().nmods()[0].fns[0].name_() == ~"a");
- }
-
- #[test]
- fn extract_mods_deep() {
- let doc = mk_doc(@"mod a { mod b { mod c { } } }");
- assert!(doc.cratemod().mods()[0].mods()[0].mods()[0].name_() ==
- ~"c");
- }
-
- #[test]
- fn extract_should_set_mod_ast_id() {
- let doc = mk_doc(@"mod a { }");
- assert!(doc.cratemod().mods()[0].id() != 0);
- }
-
- #[test]
- fn extract_fns() {
- let doc = mk_doc(
- @"fn a() { } \
- mod b { fn c() {
- } }");
- assert!(doc.cratemod().fns()[0].name_() == ~"a");
- assert!(doc.cratemod().mods()[0].fns()[0].name_() == ~"c");
- }
-
- #[test]
- fn extract_should_set_fn_ast_id() {
- let doc = mk_doc(@"fn a() { }");
- assert!(doc.cratemod().fns()[0].id() != 0);
- }
-
- #[test]
- fn extract_should_use_default_crate_name() {
- let source = @"";
- let ast = parse::from_str(source);
- let doc = extract(ast, ~"burp");
- assert!(doc.cratemod().name_() == ~"burp");
- }
-
- #[test]
- fn extract_from_seq_srv() {
- let source = ~"";
- do astsrv::from_str(source) |srv| {
- let doc = from_srv(srv, ~"name");
- assert!(doc.cratemod().name_() == ~"name");
- }
- }
-
- #[test]
- fn should_extract_static_name_and_id() {
- let doc = mk_doc(@"static a: int = 0;");
- assert!(doc.cratemod().statics()[0].id() != 0);
- assert!(doc.cratemod().statics()[0].name_() == ~"a");
- }
-
- #[test]
- fn should_extract_enums() {
- let doc = mk_doc(@"enum e { v }");
- assert!(doc.cratemod().enums()[0].id() != 0);
- assert!(doc.cratemod().enums()[0].name_() == ~"e");
- }
-
- #[test]
- fn should_extract_enum_variants() {
- let doc = mk_doc(@"enum e { v }");
- assert!(doc.cratemod().enums()[0].variants[0].name == ~"v");
- }
-
- #[test]
- fn should_extract_traits() {
- let doc = mk_doc(@"trait i { fn f(); }");
- assert!(doc.cratemod().traits()[0].name_() == ~"i");
- }
-
- #[test]
- fn should_extract_trait_methods() {
- let doc = mk_doc(@"trait i { fn f(); }");
- assert!(doc.cratemod().traits()[0].methods[0].name == ~"f");
- }
-
- #[test]
- fn should_extract_impl_methods() {
- let doc = mk_doc(@"impl int { fn f() { } }");
- assert!(doc.cratemod().impls()[0].methods[0].name == ~"f");
- }
-
- #[test]
- fn should_extract_tys() {
- let doc = mk_doc(@"type a = int;");
- assert!(doc.cratemod().types()[0].name_() == ~"a");
- }
-
- #[test]
- fn should_extract_structs() {
- let doc = mk_doc(@"struct Foo { field: () }");
- assert!(doc.cratemod().structs()[0].name_() == ~"Foo");
- }
-
- #[test]
- fn should_extract_struct_fields() {
- let doc = mk_doc(@"struct Foo { field: () }");
- assert!(doc.cratemod().structs()[0].fields[0] == ~"field");
- }
-}
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-use doc;
-#[cfg(test)] use extract;
-#[cfg(test)] use parse;
-
-pub struct Fold<T> {
- ctxt: T,
- fold_doc: FoldDoc<T>,
- fold_crate: FoldCrate<T>,
- fold_item: FoldItem<T>,
- fold_mod: FoldMod<T>,
- fold_nmod: FoldNmod<T>,
- fold_fn: FoldFn<T>,
- fold_static: FoldStatic<T>,
- fold_enum: FoldEnum<T>,
- fold_trait: FoldTrait<T>,
- fold_impl: FoldImpl<T>,
- fold_type: FoldType<T>,
- fold_struct: FoldStruct<T>
-}
-
-impl<T:Clone> Clone for Fold<T> {
- fn clone(&self) -> Fold<T> {
- Fold {
- ctxt: self.ctxt.clone(),
- fold_doc: self.fold_doc,
- fold_crate: self.fold_crate,
- fold_item: self.fold_item,
- fold_mod: self.fold_mod,
- fold_nmod: self.fold_nmod,
- fold_fn: self.fold_fn,
- fold_static: self.fold_static,
- fold_enum: self.fold_enum,
- fold_trait: self.fold_trait,
- fold_impl: self.fold_impl,
- fold_type: self.fold_type,
- fold_struct: self.fold_struct
- }
- }
-}
-
-type FoldDoc<T> = @fn(fold: &Fold<T>, doc: doc::Doc) -> doc::Doc;
-type FoldCrate<T> = @fn(fold: &Fold<T>, doc: doc::CrateDoc) -> doc::CrateDoc;
-type FoldItem<T> = @fn(fold: &Fold<T>, doc: doc::ItemDoc) -> doc::ItemDoc;
-type FoldMod<T> = @fn(fold: &Fold<T>, doc: doc::ModDoc) -> doc::ModDoc;
-type FoldNmod<T> = @fn(fold: &Fold<T>, doc: doc::NmodDoc) -> doc::NmodDoc;
-type FoldFn<T> = @fn(fold: &Fold<T>, doc: doc::FnDoc) -> doc::FnDoc;
-type FoldStatic<T> = @fn(fold: &Fold<T>, doc: doc::StaticDoc) -> doc::StaticDoc;
-type FoldEnum<T> = @fn(fold: &Fold<T>, doc: doc::EnumDoc) -> doc::EnumDoc;
-type FoldTrait<T> = @fn(fold: &Fold<T>, doc: doc::TraitDoc) -> doc::TraitDoc;
-type FoldImpl<T> = @fn(fold: &Fold<T>, doc: doc::ImplDoc) -> doc::ImplDoc;
-type FoldType<T> = @fn(fold: &Fold<T>, doc: doc::TyDoc) -> doc::TyDoc;
-type FoldStruct<T> = @fn(fold: &Fold<T>,
- doc: doc::StructDoc) -> doc::StructDoc;
-
-// This exists because fn types don't infer correctly as record
-// initializers, but they do as function arguments
-fn mk_fold<T>(
- ctxt: T,
- fold_doc: FoldDoc<T>,
- fold_crate: FoldCrate<T>,
- fold_item: FoldItem<T>,
- fold_mod: FoldMod<T>,
- fold_nmod: FoldNmod<T>,
- fold_fn: FoldFn<T>,
- fold_static: FoldStatic<T>,
- fold_enum: FoldEnum<T>,
- fold_trait: FoldTrait<T>,
- fold_impl: FoldImpl<T>,
- fold_type: FoldType<T>,
- fold_struct: FoldStruct<T>
-) -> Fold<T> {
- Fold {
- ctxt: ctxt,
- fold_doc: fold_doc,
- fold_crate: fold_crate,
- fold_item: fold_item,
- fold_mod: fold_mod,
- fold_nmod: fold_nmod,
- fold_fn: fold_fn,
- fold_static: fold_static,
- fold_enum: fold_enum,
- fold_trait: fold_trait,
- fold_impl: fold_impl,
- fold_type: fold_type,
- fold_struct: fold_struct
- }
-}
-
-pub fn default_any_fold<T:Clone>(ctxt: T) -> Fold<T> {
- mk_fold(
- ctxt,
- |f, d| default_seq_fold_doc(f, d),
- |f, d| default_seq_fold_crate(f, d),
- |f, d| default_seq_fold_item(f, d),
- |f, d| default_any_fold_mod(f, d),
- |f, d| default_any_fold_nmod(f, d),
- |f, d| default_seq_fold_fn(f, d),
- |f, d| default_seq_fold_static(f, d),
- |f, d| default_seq_fold_enum(f, d),
- |f, d| default_seq_fold_trait(f, d),
- |f, d| default_seq_fold_impl(f, d),
- |f, d| default_seq_fold_type(f, d),
- |f, d| default_seq_fold_struct(f, d)
- )
-}
-
-pub fn default_seq_fold<T:Clone>(ctxt: T) -> Fold<T> {
- mk_fold(
- ctxt,
- |f, d| default_seq_fold_doc(f, d),
- |f, d| default_seq_fold_crate(f, d),
- |f, d| default_seq_fold_item(f, d),
- |f, d| default_seq_fold_mod(f, d),
- |f, d| default_seq_fold_nmod(f, d),
- |f, d| default_seq_fold_fn(f, d),
- |f, d| default_seq_fold_static(f, d),
- |f, d| default_seq_fold_enum(f, d),
- |f, d| default_seq_fold_trait(f, d),
- |f, d| default_seq_fold_impl(f, d),
- |f, d| default_seq_fold_type(f, d),
- |f, d| default_seq_fold_struct(f, d)
- )
-}
-
-pub fn default_par_fold<T:Clone>(ctxt: T) -> Fold<T> {
- mk_fold(
- ctxt,
- |f, d| default_seq_fold_doc(f, d),
- |f, d| default_seq_fold_crate(f, d),
- |f, d| default_seq_fold_item(f, d),
- |f, d| default_par_fold_mod(f, d),
- |f, d| default_par_fold_nmod(f, d),
- |f, d| default_seq_fold_fn(f, d),
- |f, d| default_seq_fold_static(f, d),
- |f, d| default_seq_fold_enum(f, d),
- |f, d| default_seq_fold_trait(f, d),
- |f, d| default_seq_fold_impl(f, d),
- |f, d| default_seq_fold_type(f, d),
- |f, d| default_seq_fold_struct(f, d)
- )
-}
-
-pub fn default_seq_fold_doc<T>(fold: &Fold<T>, doc: doc::Doc) -> doc::Doc {
- doc::Doc {
- pages: do doc.pages.iter().map |page| {
- match (*page).clone() {
- doc::CratePage(doc) => {
- doc::CratePage((fold.fold_crate)(fold, doc))
- }
- doc::ItemPage(doc) => {
- doc::ItemPage(fold_ItemTag(fold, doc))
- }
- }
- }.collect(),
- .. doc
- }
-}
-
-pub fn default_seq_fold_crate<T>(
- fold: &Fold<T>,
- doc: doc::CrateDoc
-) -> doc::CrateDoc {
- doc::CrateDoc {
- topmod: (fold.fold_mod)(fold, doc.topmod.clone())
- }
-}
-
-pub fn default_seq_fold_item<T>(
- _fold: &Fold<T>,
- doc: doc::ItemDoc
-) -> doc::ItemDoc {
- doc
-}
-
-pub fn default_any_fold_mod<T:Clone>(
- fold: &Fold<T>,
- doc: doc::ModDoc
-) -> doc::ModDoc {
- doc::ModDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- items: doc.items.iter().map(|ItemTag| {
- fold_ItemTag(fold, (*ItemTag).clone())
- }).collect(),
- .. doc
- }
-}
-
-pub fn default_seq_fold_mod<T>(
- fold: &Fold<T>,
- doc: doc::ModDoc
-) -> doc::ModDoc {
- doc::ModDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- items: doc.items.iter().map(|ItemTag| {
- fold_ItemTag(fold, (*ItemTag).clone())
- }).collect(),
- .. doc
- }
-}
-
-pub fn default_par_fold_mod<T:Clone>(
- fold: &Fold<T>,
- doc: doc::ModDoc
-) -> doc::ModDoc {
- doc::ModDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- items: doc.items.iter().map(|ItemTag| {
- fold_ItemTag(fold, (*ItemTag).clone())
- }).collect(),
- .. doc
- }
-}
-
-pub fn default_any_fold_nmod<T:Clone>(
- fold: &Fold<T>,
- doc: doc::NmodDoc
-) -> doc::NmodDoc {
- doc::NmodDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- fns: doc.fns.iter().map(|FnDoc| {
- (fold.fold_fn)(fold, (*FnDoc).clone())
- }).collect(),
- .. doc
- }
-}
-
-pub fn default_seq_fold_nmod<T>(
- fold: &Fold<T>,
- doc: doc::NmodDoc
-) -> doc::NmodDoc {
- doc::NmodDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- fns: doc.fns.iter().map(|FnDoc| {
- (fold.fold_fn)(fold, (*FnDoc).clone())
- }).collect(),
- .. doc
- }
-}
-
-pub fn default_par_fold_nmod<T:Clone>(
- fold: &Fold<T>,
- doc: doc::NmodDoc
-) -> doc::NmodDoc {
- doc::NmodDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- fns: doc.fns.iter().map(|FnDoc| {
- (fold.fold_fn)(fold, (*FnDoc).clone())
- }).collect(),
- .. doc
- }
-}
-
-pub fn fold_ItemTag<T>(fold: &Fold<T>, doc: doc::ItemTag) -> doc::ItemTag {
- match doc {
- doc::ModTag(ModDoc) => {
- doc::ModTag((fold.fold_mod)(fold, ModDoc))
- }
- doc::NmodTag(nModDoc) => {
- doc::NmodTag((fold.fold_nmod)(fold, nModDoc))
- }
- doc::FnTag(FnDoc) => {
- doc::FnTag((fold.fold_fn)(fold, FnDoc))
- }
- doc::StaticTag(StaticDoc) => {
- doc::StaticTag((fold.fold_static)(fold, StaticDoc))
- }
- doc::EnumTag(EnumDoc) => {
- doc::EnumTag((fold.fold_enum)(fold, EnumDoc))
- }
- doc::TraitTag(TraitDoc) => {
- doc::TraitTag((fold.fold_trait)(fold, TraitDoc))
- }
- doc::ImplTag(ImplDoc) => {
- doc::ImplTag((fold.fold_impl)(fold, ImplDoc))
- }
- doc::TyTag(TyDoc) => {
- doc::TyTag((fold.fold_type)(fold, TyDoc))
- }
- doc::StructTag(StructDoc) => {
- doc::StructTag((fold.fold_struct)(fold, StructDoc))
- }
- }
-}
-
-pub fn default_seq_fold_fn<T>(
- fold: &Fold<T>,
- doc: doc::FnDoc
-) -> doc::FnDoc {
- doc::SimpleItemDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- .. doc
- }
-}
-
-pub fn default_seq_fold_static<T>(
- fold: &Fold<T>,
- doc: doc::StaticDoc
-) -> doc::StaticDoc {
- doc::SimpleItemDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- .. doc
- }
-}
-
-pub fn default_seq_fold_enum<T>(
- fold: &Fold<T>,
- doc: doc::EnumDoc
-) -> doc::EnumDoc {
- doc::EnumDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- .. doc
- }
-}
-
-pub fn default_seq_fold_trait<T>(
- fold: &Fold<T>,
- doc: doc::TraitDoc
-) -> doc::TraitDoc {
- doc::TraitDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- .. doc
- }
-}
-
-pub fn default_seq_fold_impl<T>(
- fold: &Fold<T>,
- doc: doc::ImplDoc
-) -> doc::ImplDoc {
- doc::ImplDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- .. doc
- }
-}
-
-pub fn default_seq_fold_type<T>(
- fold: &Fold<T>,
- doc: doc::TyDoc
-) -> doc::TyDoc {
- doc::SimpleItemDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- .. doc
- }
-}
-
-pub fn default_seq_fold_struct<T>(
- fold: &Fold<T>,
- doc: doc::StructDoc
-) -> doc::StructDoc {
- doc::StructDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- .. doc
+use std;
+use clean::*;
+use std::iter::Extendable;
+
+pub trait DocFolder {
+ fn fold_item(&mut self, item: Item) -> Option<Item> {
+ self.fold_item_recur(item)
+ }
+
+ /// don't override!
+ fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
+ use std::util::swap;
+ let Item { attrs, name, source, visibility, id, inner } = item;
+ let inner = inner;
+ let c = |x| self.fold_item(x);
+ let inner = match inner {
+ StructItem(i) => {
+ let mut i = i;
+ let mut foo = ~[]; swap(&mut foo, &mut i.fields);
+ i.fields.extend(&mut foo.move_iter().filter_map(|x| self.fold_item(x)));
+ StructItem(i)
+ },
+ ModuleItem(i) => {
+ ModuleItem(self.fold_mod(i))
+ },
+ EnumItem(i) => {
+ let mut i = i;
+ let mut foo = ~[]; swap(&mut foo, &mut i.variants);
+ i.variants.extend(&mut foo.move_iter().filter_map(|x| self.fold_item(x)));
+ EnumItem(i)
+ },
+ TraitItem(i) => {
+ fn vtrm<T: DocFolder>(this: &mut T, trm: TraitMethod) -> Option<TraitMethod> {
+ match trm {
+ Required(it) => {
+ match this.fold_item(it) {
+ Some(x) => return Some(Required(x)),
+ None => return None,
+ }
+ },
+ Provided(it) => {
+ match this.fold_item(it) {
+ Some(x) => return Some(Provided(x)),
+ None => return None,
+ }
+ },
+ }
+ }
+ let mut i = i;
+ let mut foo = ~[]; swap(&mut foo, &mut i.methods);
+ i.methods.extend(&mut foo.move_iter().filter_map(|x| vtrm(self, x)));
+ TraitItem(i)
+ },
+ ImplItem(i) => {
+ let mut i = i;
+ let mut foo = ~[]; swap(&mut foo, &mut i.methods);
+ i.methods.extend(&mut foo.move_iter().filter_map(|x| self.fold_item(x)));
+ ImplItem(i)
+ },
+ VariantItem(i) => {
+ let i2 = i.clone(); // this clone is small
+ match i.kind {
+ StructVariant(j) => {
+ let mut j = j;
+ let mut foo = ~[]; swap(&mut foo, &mut j.fields);
+ j.fields.extend(&mut foo.move_iter().filter_map(c));
+ VariantItem(Variant {kind: StructVariant(j), ..i2})
+ },
+ _ => VariantItem(i2)
+ }
+ },
+ x => x
+ };
+
+ Some(Item { attrs: attrs, name: name, source: source, inner: inner,
+ visibility: visibility, id: id })
+ }
+
+ fn fold_mod(&mut self, m: Module) -> Module {
+ Module { items: m.items.move_iter().filter_map(|i| self.fold_item(i)).collect() }
+ }
+
+ fn fold_crate(&mut self, mut c: Crate) -> Crate {
+ c.module = match std::util::replace(&mut c.module, None) {
+ Some(module) => self.fold_item(module), None => None
+ };
+ return c;
}
}
-
-#[test]
-fn default_fold_should_produce_same_doc() {
- let source = @"mod a { fn b() { } mod c { fn d() { } } }";
- let ast = parse::from_str(source);
- let doc = extract::extract(ast, ~"");
- let fld = default_seq_fold(());
- let folded = (fld.fold_doc)(&fld, doc.clone());
- assert_eq!(doc, folded);
-}
-
-#[test]
-fn default_fold_should_produce_same_statics() {
- let source = @"static a: int = 0;";
- let ast = parse::from_str(source);
- let doc = extract::extract(ast, ~"");
- let fld = default_seq_fold(());
- let folded = (fld.fold_doc)(&fld, doc.clone());
- assert_eq!(doc, folded);
-}
-
-#[test]
-fn default_fold_should_produce_same_enums() {
- let source = @"enum a { b }";
- let ast = parse::from_str(source);
- let doc = extract::extract(ast, ~"");
- let fld = default_seq_fold(());
- let folded = (fld.fold_doc)(&fld, doc.clone());
- assert_eq!(doc, folded);
-}
-
-#[test]
-fn default_parallel_fold_should_produce_same_doc() {
- let source = @"mod a { fn b() { } mod c { fn d() { } } }";
- let ast = parse::from_str(source);
- let doc = extract::extract(ast, ~"");
- let fld = default_par_fold(());
- let folded = (fld.fold_doc)(&fld, doc.clone());
- assert_eq!(doc, folded);
-}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::fmt;
+use std::local_data;
+use std::rt::io;
+
+use syntax::ast;
+
+use clean;
+use html::render::{cache_key, current_location_key};
+
+pub struct VisSpace(Option<ast::visibility>);
+pub struct Method<'self>(&'self clean::SelfTy, &'self clean::FnDecl);
+
+impl fmt::Default for clean::Generics {
+ fn fmt(g: &clean::Generics, f: &mut fmt::Formatter) {
+ if g.lifetimes.len() == 0 && g.type_params.len() == 0 { return }
+ f.buf.write("<".as_bytes());
+
+ for (i, life) in g.lifetimes.iter().enumerate() {
+ if i > 0 { f.buf.write(", ".as_bytes()); }
+ write!(f.buf, "{}", *life);
+ }
+
+ if g.type_params.len() > 0 {
+ if g.lifetimes.len() > 0 { f.buf.write(", ".as_bytes()); }
+
+ for (i, tp) in g.type_params.iter().enumerate() {
+ if i > 0 { f.buf.write(", ".as_bytes()) }
+ f.buf.write(tp.name.as_bytes());
+
+ if tp.bounds.len() > 0 {
+ f.buf.write(": ".as_bytes());
+ for (i, bound) in tp.bounds.iter().enumerate() {
+ if i > 0 { f.buf.write(" + ".as_bytes()); }
+ write!(f.buf, "{}", *bound);
+ }
+ }
+ }
+ }
+ f.buf.write(">".as_bytes());
+ }
+}
+
+impl fmt::Default for clean::Lifetime {
+ fn fmt(l: &clean::Lifetime, f: &mut fmt::Formatter) {
+ f.buf.write("'".as_bytes());
+ f.buf.write(l.as_bytes());
+ }
+}
+
+impl fmt::Default for clean::TyParamBound {
+ fn fmt(bound: &clean::TyParamBound, f: &mut fmt::Formatter) {
+ match *bound {
+ clean::RegionBound => {
+ f.buf.write("'static".as_bytes())
+ }
+ clean::TraitBound(ref ty) => {
+ write!(f.buf, "{}", *ty);
+ }
+ }
+ }
+}
+
+impl fmt::Default for clean::Path {
+ fn fmt(path: &clean::Path, f: &mut fmt::Formatter) {
+ if path.global { f.buf.write("::".as_bytes()) }
+ for (i, seg) in path.segments.iter().enumerate() {
+ if i > 0 { f.buf.write("::".as_bytes()) }
+ f.buf.write(seg.name.as_bytes());
+
+ if seg.lifetime.is_some() || seg.types.len() > 0 {
+ f.buf.write("<".as_bytes());
+ match seg.lifetime {
+ Some(ref lifetime) => write!(f.buf, "{}", *lifetime),
+ None => {}
+ }
+ for (i, ty) in seg.types.iter().enumerate() {
+ if i > 0 || seg.lifetime.is_some() {
+ f.buf.write(", ".as_bytes());
+ }
+ write!(f.buf, "{}", *ty);
+ }
+ f.buf.write(">".as_bytes());
+ }
+ }
+ }
+}
+
+fn resolved_path(w: &mut io::Writer, id: ast::NodeId, path: &clean::Path) {
+ // The generics will get written to both the title and link
+ let mut generics = ~"";
+ let last = path.segments.last();
+ if last.lifetime.is_some() || last.types.len() > 0 {
+ generics.push_str("<");
+ match last.lifetime {
+ Some(ref lifetime) => generics.push_str(format!("{}", *lifetime)),
+ None => {}
+ }
+ for (i, ty) in last.types.iter().enumerate() {
+ if i > 0 || last.lifetime.is_some() {
+ generics.push_str(", ");
+ }
+ generics.push_str(format!("{}", *ty));
+ }
+ generics.push_str(">");
+ }
+
+ // Did someone say rightward-drift?
+ do local_data::get(current_location_key) |loc| {
+ let loc = loc.unwrap();
+ do local_data::get(cache_key) |cache| {
+ do cache.unwrap().read |cache| {
+ match cache.paths.find(&id) {
+ // This is a documented path, link to it!
+ Some(&(ref fqp, shortty)) => {
+ let fqn = fqp.connect("::");
+ let mut same = 0;
+ for (a, b) in loc.iter().zip(fqp.iter()) {
+ if *a == *b {
+ same += 1;
+ } else {
+ break;
+ }
+ }
+
+ let mut url = ~"";
+ for _ in range(same, loc.len()) {
+ url.push_str("../");
+ }
+ if same == fqp.len() {
+ url.push_str(shortty);
+ url.push_str(".");
+ url.push_str(*fqp.last());
+ url.push_str(".html");
+ } else {
+ let remaining = fqp.slice_from(same);
+ let to_link = remaining.slice_to(remaining.len() - 1);
+ for component in to_link.iter() {
+ url.push_str(*component);
+ url.push_str("/");
+ }
+ url.push_str(shortty);
+ url.push_str(".");
+ url.push_str(*remaining.last());
+ url.push_str(".html");
+ }
+
+ write!(w, "<a class='{}' href='{}' title='{}'>{}</a>{}",
+ shortty, url, fqn, last.name, generics);
+ }
+ None => {
+ write!(w, "{}{}", last.name, generics);
+ }
+ };
+ }
+ }
+ }
+}
+
+impl fmt::Default for clean::Type {
+ fn fmt(g: &clean::Type, f: &mut fmt::Formatter) {
+ match *g {
+ clean::TyParamBinder(id) | clean::Generic(id) => {
+ do local_data::get(cache_key) |cache| {
+ do cache.unwrap().read |m| {
+ f.buf.write(m.typarams.get(&id).as_bytes());
+ }
+ }
+ }
+ clean::Unresolved(*) => unreachable!(),
+ clean::ResolvedPath{id, typarams: ref typarams, path: ref path} => {
+ resolved_path(f.buf, id, path);
+ match *typarams {
+ Some(ref params) => {
+ f.buf.write("<".as_bytes());
+ for (i, param) in params.iter().enumerate() {
+ if i > 0 { f.buf.write(", ".as_bytes()) }
+ write!(f.buf, "{}", *param);
+ }
+ f.buf.write(">".as_bytes());
+ }
+ None => {}
+ }
+ }
+ // XXX: this should be a link
+ clean::External(ref a, _) => {
+ write!(f.buf, "{}", *a);
+ }
+ clean::Self(*) => f.buf.write("Self".as_bytes()),
+ clean::Primitive(prim) => {
+ let s = match prim {
+ ast::ty_int(ast::ty_i) => "int",
+ ast::ty_int(ast::ty_i8) => "i8",
+ ast::ty_int(ast::ty_i16) => "i16",
+ ast::ty_int(ast::ty_i32) => "i32",
+ ast::ty_int(ast::ty_i64) => "i64",
+ ast::ty_uint(ast::ty_u) => "uint",
+ ast::ty_uint(ast::ty_u8) => "u8",
+ ast::ty_uint(ast::ty_u16) => "u16",
+ ast::ty_uint(ast::ty_u32) => "u32",
+ ast::ty_uint(ast::ty_u64) => "u64",
+ ast::ty_float(ast::ty_f) => "float",
+ ast::ty_float(ast::ty_f32) => "f32",
+ ast::ty_float(ast::ty_f64) => "f64",
+ ast::ty_str => "str",
+ ast::ty_bool => "bool",
+ ast::ty_char => "char",
+ };
+ f.buf.write(s.as_bytes());
+ }
+ clean::Closure(ref decl) => {
+ f.buf.write(match decl.sigil {
+ ast::BorrowedSigil => "&",
+ ast::ManagedSigil => "@",
+ ast::OwnedSigil => "~",
+ }.as_bytes());
+ match decl.region {
+ Some(ref region) => write!(f.buf, "{} ", *region),
+ None => {}
+ }
+ write!(f.buf, "{}{}fn{}",
+ match decl.purity {
+ ast::unsafe_fn => "unsafe ",
+ ast::extern_fn => "extern ",
+ ast::impure_fn => ""
+ },
+ match decl.onceness {
+ ast::Once => "once ",
+ ast::Many => "",
+ },
+ decl.decl);
+ // XXX: where are bounds and lifetimes printed?!
+ }
+ clean::BareFunction(ref decl) => {
+ write!(f.buf, "{}{}fn{}{}",
+ match decl.purity {
+ ast::unsafe_fn => "unsafe ",
+ ast::extern_fn => "extern ",
+ ast::impure_fn => ""
+ },
+ match decl.abi {
+ ~"" | ~"\"Rust\"" => ~"",
+ ref s => " " + *s + " ",
+ },
+ decl.generics,
+ decl.decl);
+ }
+ clean::Tuple(ref typs) => {
+ f.buf.write("(".as_bytes());
+ for (i, typ) in typs.iter().enumerate() {
+ if i > 0 { f.buf.write(", ".as_bytes()) }
+ write!(f.buf, "{}", *typ);
+ }
+ f.buf.write(")".as_bytes());
+ }
+ clean::Vector(ref t) => write!(f.buf, "[{}]", **t),
+ clean::FixedVector(ref t, ref s) => {
+ write!(f.buf, "[{}, ..{}]", **t, *s);
+ }
+ clean::String => f.buf.write("str".as_bytes()),
+ clean::Bool => f.buf.write("bool".as_bytes()),
+ clean::Unit => f.buf.write("()".as_bytes()),
+ clean::Bottom => f.buf.write("!".as_bytes()),
+ clean::Unique(ref t) => write!(f.buf, "~{}", **t),
+ clean::Managed(m, ref t) => {
+ write!(f.buf, "@{}{}",
+ match m {
+ clean::Mutable => "mut ",
+ clean::Immutable => "",
+ }, **t)
+ }
+ clean::RawPointer(m, ref t) => {
+ write!(f.buf, "*{}{}",
+ match m {
+ clean::Mutable => "mut ",
+ clean::Immutable => "",
+ }, **t)
+ }
+ clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
+ let lt = match *l { Some(ref l) => format!("{} ", *l), _ => ~"" };
+ write!(f.buf, "&{}{}{}",
+ lt,
+ match mutability {
+ clean::Mutable => "mut ",
+ clean::Immutable => "",
+ },
+ **ty);
+ }
+ }
+ }
+}
+
+impl fmt::Default for clean::FnDecl {
+ fn fmt(d: &clean::FnDecl, f: &mut fmt::Formatter) {
+ let mut args = ~"";
+ for (i, input) in d.inputs.iter().enumerate() {
+ if i > 0 { args.push_str(", "); }
+ if input.name.len() > 0 {
+ args.push_str(format!("{}: ", input.name));
+ }
+ args.push_str(format!("{}", input.type_));
+ }
+ write!(f.buf, "({args}){arrow, select, yes{ -> {ret}} other{}}",
+ args = args,
+ arrow = match d.output { clean::Unit => "no", _ => "yes" },
+ ret = d.output);
+ }
+}
+
+impl<'self> fmt::Default for Method<'self> {
+ fn fmt(m: &Method<'self>, f: &mut fmt::Formatter) {
+ let Method(selfty, d) = *m;
+ let mut args = ~"";
+ match *selfty {
+ clean::SelfStatic => {},
+ clean::SelfValue => args.push_str("self"),
+ clean::SelfOwned => args.push_str("~self"),
+ clean::SelfManaged(clean::Mutable) => args.push_str("@mut self"),
+ clean::SelfManaged(clean::Immutable) => args.push_str("@self"),
+ clean::SelfBorrowed(Some(ref lt), clean::Immutable) => {
+ args.push_str(format!("&{} self", *lt));
+ }
+ clean::SelfBorrowed(Some(ref lt), clean::Mutable) => {
+ args.push_str(format!("&{} mut self", *lt));
+ }
+ clean::SelfBorrowed(None, clean::Mutable) => {
+ args.push_str("&mut self");
+ }
+ clean::SelfBorrowed(None, clean::Immutable) => {
+ args.push_str("&self");
+ }
+ }
+ for (i, input) in d.inputs.iter().enumerate() {
+ if i > 0 || args.len() > 0 { args.push_str(", "); }
+ if input.name.len() > 0 {
+ args.push_str(format!("{}: ", input.name));
+ }
+ args.push_str(format!("{}", input.type_));
+ }
+ write!(f.buf, "({args}){arrow, select, yes{ -> {ret}} other{}}",
+ args = args,
+ arrow = match d.output { clean::Unit => "no", _ => "yes" },
+ ret = d.output);
+ }
+}
+
+impl fmt::Default for VisSpace {
+ fn fmt(v: &VisSpace, f: &mut fmt::Formatter) {
+ match **v {
+ Some(ast::public) => { write!(f.buf, "pub "); }
+ Some(ast::private) => { write!(f.buf, "priv "); }
+ Some(ast::inherited) | None => {}
+ }
+ }
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::fmt;
+use std::rt::io;
+
+#[deriving(Clone)]
+pub struct Layout {
+ logo: ~str,
+ favicon: ~str,
+ crate: ~str,
+}
+
+pub struct Page<'self> {
+ title: &'self str,
+ ty: &'self str,
+ root_path: &'self str,
+}
+
+pub fn render<T: fmt::Default, S: fmt::Default>(
+ dst: &mut io::Writer, layout: &Layout, page: &Page, sidebar: &S, t: &T)
+{
+ write!(dst, "
+<!DOCTYPE html>
+<html lang=\"en\">
+<head>
+ <meta charset=\"utf-8\" />
+ <title>{title}</title>
+
+ <link href='http://fonts.googleapis.com/css?family=Oswald:700|Inconsolata:400'
+ rel='stylesheet' type='text/css'>
+ <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}main.css\">
+
+ {favicon, select, none{} other{
+ <link rel=\"icon\" href=\"#\" sizes=\"16x16\"
+ type=\"image/vnd.microsoft.icon\" />}}
+</head>
+<body>
+ <!--[if lte IE 8]>
+ <div class=\"warning\">
+ This old browser is unsupported and will most likely display funky
+ things
+ </div>
+ <![endif]-->
+
+ <section class=\"sidebar\">
+ {logo, select, none{} other{
+ <a href='{root_path}index.html'><img src='#' alt=''/></a>
+ }}
+
+ {sidebar}
+ </section>
+
+ <nav class=\"sub\">
+ <form class=\"search-form js-only\">
+ <input class=\"search-input\" name=\"search\"
+ autocomplete=\"off\" />
+ <button class=\"do-search\">Search</button>
+ </form>
+ </nav>
+
+ <section class=\"content {ty}\">{content}</section>
+
+ <section class=\"footer\"></section>
+
+ <script>
+ var rootPath = \"{root_path}\";
+ </script>
+ <script src=\"{root_path}jquery.js\"></script>
+ <script src=\"{root_path}{crate}/search-index.js\"></script>
+ <script src=\"{root_path}main.js\"></script>
+
+ <div id=\"help\" class=\"hidden\">
+ <div class=\"shortcuts\">
+ <h1>Keyboard shortcuts</h1>
+ <dl>
+ <dt>?</dt>
+ <dd>Show this help dialog</dd>
+ <dt>S</dt>
+ <dd>Focus the search field</dd>
+ <dt>↑</dt>
+ <dd>Move up in search results</dd>
+ <dt>↓</dt>
+ <dd>Move down in search results</dd>
+ <dt>&\\#9166;</dt>
+ <dd>Go to active search result</dd>
+ </dl>
+ </div>
+ <div class=\"infos\">
+ <h1>Search tricks</h1>
+ <p>
+ Prefix searches with a type followed by a colon (e.g.
+ <code>fn:</code>) to restrict the search to a given type.
+ </p>
+ <p>
+ Accepted types are: <code>fn</code>, <code>mod</code>,
+ <code>struct</code> (or <code>str</code>), <code>enum</code>,
+ <code>trait</code>, <code>typedef</code> (or
+ <code>tdef</code>).
+ </p>
+ </div>
+ </div>
+</body>
+</html>
+",
+ content = *t,
+ root_path = page.root_path,
+ ty = page.ty,
+ logo = nonestr(layout.logo),
+ title = page.title,
+ favicon = nonestr(layout.favicon),
+ sidebar = *sidebar,
+ crate = layout.crate,
+ );
+}
+
+fn boolstr(b: bool) -> &'static str {
+ if b { "true" } else { "false" }
+}
+
+fn nonestr<'a>(s: &'a str) -> &'a str {
+ if s == "" { "none" } else { s }
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::fmt;
+use std::rt::io::Reader;
+use std::rt::io::pipe::PipeStream;
+use std::rt::io::process::{ProcessConfig, Process, CreatePipe};
+use std::rt::io;
+
+pub struct Markdown<'self>(&'self str);
+
+impl<'self> fmt::Default for Markdown<'self> {
+ fn fmt(md: &Markdown<'self>, fmt: &mut fmt::Formatter) {
+ if md.len() == 0 { return; }
+
+ // Create the pandoc process
+ do io::io_error::cond.trap(|err| {
+ fail2!("Error executing `pandoc`: {}", err.desc);
+ }).inside {
+ let io = ~[CreatePipe(PipeStream::new().unwrap(), true, false),
+ CreatePipe(PipeStream::new().unwrap(), false, true)];
+ let args = ProcessConfig {
+ program: "pandoc",
+ args: [],
+ env: None,
+ cwd: None,
+ io: io,
+ };
+ let mut p = Process::new(args).expect("couldn't fork for pandoc");
+
+ // Write the markdown to stdin and close it.
+ p.io[0].get_mut_ref().write(md.as_bytes());
+ p.io[0] = None;
+
+ // Ferry the output from pandoc over to the destination buffer.
+ let mut buf = [0, ..1024];
+ loop {
+ match p.io[1].get_mut_ref().read(buf) {
+ None | Some(0) => { break }
+ Some(n) => {
+ fmt.buf.write(buf.slice_to(n));
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cell::Cell;
+use std::comm::{SharedPort, SharedChan};
+use std::comm;
+use std::fmt;
+use std::hashmap::HashMap;
+use std::local_data;
+use std::rt::io::buffered::BufferedWriter;
+use std::rt::io::file::{FileInfo, DirectoryInfo};
+use std::rt::io::file;
+use std::rt::io;
+use std::task;
+use std::unstable::finally::Finally;
+use std::util;
+use std::vec;
+
+use extra::arc::RWArc;
+use extra::json::ToJson;
+use extra::sort;
+
+use syntax::ast;
+
+use clean;
+use doctree;
+use fold::DocFolder;
+use html::format::{VisSpace, Method};
+use html::layout;
+use html::markdown::Markdown;
+
+#[deriving(Clone)]
+pub struct Context {
+ current: ~[~str],
+ root_path: ~str,
+ dst: Path,
+ layout: layout::Layout,
+ sidebar: HashMap<~str, ~[~str]>,
+}
+
+enum Implementor {
+ PathType(clean::Type),
+ OtherType(clean::Generics, /* trait */ clean::Type, /* for */ clean::Type),
+}
+
+struct Cache {
+ // typaram id => name of that typaram
+ typarams: HashMap<ast::NodeId, ~str>,
+ // type id => all implementations for that type
+ impls: HashMap<ast::NodeId, ~[clean::Impl]>,
+ // path id => (full qualified path, shortty) -- used to generate urls
+ paths: HashMap<ast::NodeId, (~[~str], &'static str)>,
+ // trait id => method name => dox
+ traits: HashMap<ast::NodeId, HashMap<~str, ~str>>,
+ // trait id => implementors of the trait
+ implementors: HashMap<ast::NodeId, ~[Implementor]>,
+
+ priv stack: ~[~str],
+ priv parent_stack: ~[ast::NodeId],
+ priv search_index: ~[IndexItem],
+}
+
+struct Item<'self> { cx: &'self Context, item: &'self clean::Item, }
+struct Sidebar<'self> { cx: &'self Context, item: &'self clean::Item, }
+
+struct IndexItem {
+ ty: &'static str,
+ name: ~str,
+ path: ~str,
+ desc: ~str,
+ parent: Option<ast::NodeId>,
+}
+
+local_data_key!(pub cache_key: RWArc<Cache>)
+local_data_key!(pub current_location_key: ~[~str])
+
+/// Generates the documentation for `crate` into the directory `dst`
+pub fn run(mut crate: clean::Crate, dst: Path) {
+ let mut cx = Context {
+ dst: dst,
+ current: ~[],
+ root_path: ~"",
+ sidebar: HashMap::new(),
+ layout: layout::Layout {
+ logo: ~"",
+ favicon: ~"",
+ crate: crate.name.clone(),
+ },
+ };
+ mkdir(&cx.dst);
+
+ match crate.module.get_ref().doc_list() {
+ Some(attrs) => {
+ for attr in attrs.iter() {
+ match *attr {
+ clean::NameValue(~"html_favicon_url", ref s) => {
+ cx.layout.favicon = s.to_owned();
+ }
+ clean::NameValue(~"html_logo_url", ref s) => {
+ cx.layout.logo = s.to_owned();
+ }
+ _ => {}
+ }
+ }
+ }
+ None => {}
+ }
+
+ // Crawl the crate to build various caches used for the output
+ let mut cache = Cache {
+ impls: HashMap::new(),
+ typarams: HashMap::new(),
+ paths: HashMap::new(),
+ traits: HashMap::new(),
+ implementors: HashMap::new(),
+ stack: ~[],
+ parent_stack: ~[],
+ search_index: ~[],
+ };
+ cache.stack.push(crate.name.clone());
+ crate = cache.fold_crate(crate);
+
+ // Add all the static files
+ write(cx.dst.push("jquery.js"), include_str!("static/jquery-2.0.3.min.js"));
+ write(cx.dst.push("main.js"), include_str!("static/main.js"));
+ write(cx.dst.push("main.css"), include_str!("static/main.css"));
+ write(cx.dst.push("normalize.css"), include_str!("static/normalize.css"));
+ write(cx.dst.push("index.html"), format!("
+ <DOCTYPE html><html><head>
+ <meta http-equiv='refresh'
+ content=\"0; url={}/index.html\">
+ </head><body></body></html>
+ ", crate.name));
+
+ {
+ mkdir(&cx.dst.push(crate.name));
+ let dst = cx.dst.push(crate.name).push("search-index.js");
+ let mut w = BufferedWriter::new(dst.open_writer(io::CreateOrTruncate));
+ let w = &mut w as &mut io::Writer;
+ write!(w, "var searchIndex = [");
+ for (i, item) in cache.search_index.iter().enumerate() {
+ if i > 0 { write!(w, ","); }
+ write!(w, "\\{ty:\"{}\",name:\"{}\",path:\"{}\",desc:{}",
+ item.ty, item.name, item.path,
+ item.desc.to_json().to_str())
+ match item.parent {
+ Some(id) => { write!(w, ",parent:'{}'", id); }
+ None => {}
+ }
+ write!(w, "\\}");
+ }
+ write!(w, "];");
+ write!(w, "var allPaths = \\{");
+ for (i, (&id, &(ref fqp, short))) in cache.paths.iter().enumerate() {
+ if i > 0 { write!(w, ","); }
+ write!(w, "'{}':\\{type:'{}',name:'{}'\\}", id, short, *fqp.last());
+ }
+ write!(w, "\\};");
+ w.flush();
+ }
+
+ // Now render the whole crate.
+ cx.crate(crate, cache);
+}
+
+fn write(dst: Path, contents: &str) {
+ let mut w = dst.open_writer(io::CreateOrTruncate);
+ w.write(contents.as_bytes());
+}
+
+fn mkdir(path: &Path) {
+ do io::io_error::cond.trap(|err| {
+ error2!("Couldn't create directory `{}`: {}",
+ path.to_str(), err.desc);
+ fail!()
+ }).inside {
+ if !path.is_dir() {
+ file::mkdir(path);
+ }
+ }
+}
+
+impl<'self> DocFolder for Cache {
+ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+ // Register any generics to their corresponding string. This is used
+ // when pretty-printing types
+ match item.inner {
+ clean::StructItem(ref s) => self.generics(&s.generics),
+ clean::EnumItem(ref e) => self.generics(&e.generics),
+ clean::FunctionItem(ref f) => self.generics(&f.generics),
+ clean::TypedefItem(ref t) => self.generics(&t.generics),
+ clean::TraitItem(ref t) => self.generics(&t.generics),
+ clean::ImplItem(ref i) => self.generics(&i.generics),
+ clean::TyMethodItem(ref i) => self.generics(&i.generics),
+ clean::MethodItem(ref i) => self.generics(&i.generics),
+ _ => {}
+ }
+
+ // Propagate a trait methods' documentation to all implementors of the
+ // trait
+ match item.inner {
+ clean::TraitItem(ref t) => {
+ let mut dox = HashMap::new();
+ for meth in t.methods.iter() {
+ let it = meth.item();
+ match it.doc_value() {
+ None => {}
+ Some(s) => {
+ dox.insert(it.name.get_ref().to_owned(),
+ s.to_owned());
+ }
+ }
+ }
+ self.traits.insert(item.id, dox);
+ }
+ _ => {}
+ }
+
+ // Collect all the implementors of traits.
+ match item.inner {
+ clean::ImplItem(ref i) => {
+ match i.trait_ {
+ Some(clean::ResolvedPath{ id, _ }) => {
+ let v = do self.implementors.find_or_insert_with(id) |_|{
+ ~[]
+ };
+ match i.for_ {
+ clean::ResolvedPath{_} => {
+ v.unshift(PathType(i.for_.clone()));
+ }
+ _ => {
+ v.push(OtherType(i.generics.clone(),
+ i.trait_.get_ref().clone(),
+ i.for_.clone()));
+ }
+ }
+ }
+ Some(*) | None => {}
+ }
+ }
+ _ => {}
+ }
+
+ // Index this method for searching later on
+ match item.name {
+ Some(ref s) => {
+ let parent = match item.inner {
+ clean::TyMethodItem(*) | clean::VariantItem(*) => {
+ Some((Some(*self.parent_stack.last()),
+ self.stack.slice_to(self.stack.len() - 1)))
+
+ }
+ clean::MethodItem(*) => {
+ if self.parent_stack.len() == 0 {
+ None
+ } else {
+ Some((Some(*self.parent_stack.last()),
+ self.stack.as_slice()))
+ }
+ }
+ _ => Some((None, self.stack.as_slice()))
+ };
+ match parent {
+ Some((parent, path)) => {
+ self.search_index.push(IndexItem {
+ ty: shortty(&item),
+ name: s.to_owned(),
+ path: path.connect("::"),
+ desc: shorter(item.doc_value()).to_owned(),
+ parent: parent,
+ });
+ }
+ None => {}
+ }
+ }
+ None => {}
+ }
+
+ // Keep track of the fully qualified path for this item.
+ let pushed = if item.name.is_some() {
+ let n = item.name.get_ref();
+ if n.len() > 0 {
+ self.stack.push(n.to_owned());
+ true
+ } else { false }
+ } else { false };
+ match item.inner {
+ clean::StructItem(*) | clean::EnumItem(*) |
+ clean::TypedefItem(*) | clean::TraitItem(*) => {
+ self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
+ }
+ _ => {}
+ }
+
+ // Maintain the parent stack
+ let parent_pushed = match item.inner {
+ clean::TraitItem(*) | clean::EnumItem(*) => {
+ self.parent_stack.push(item.id); true
+ }
+ clean::ImplItem(ref i) => {
+ match i.for_ {
+ clean::ResolvedPath{ id, _ } => {
+ self.parent_stack.push(id); true
+ }
+ _ => false
+ }
+ }
+ _ => false
+ };
+
+ // Once we've recursively found all the generics, then hoard off all the
+ // implementations elsewhere
+ let ret = match self.fold_item_recur(item) {
+ Some(item) => {
+ match item.inner {
+ clean::ImplItem(i) => {
+ match i.for_ {
+ clean::ResolvedPath { id, _ } => {
+ let v = do self.impls.find_or_insert_with(id) |_| {
+ ~[]
+ };
+ v.push(i);
+ }
+ _ => {}
+ }
+ None
+ }
+ _ => Some(item),
+ }
+ }
+ i => i,
+ };
+
+ if pushed { self.stack.pop(); }
+ if parent_pushed { self.parent_stack.pop(); }
+ return ret;
+ }
+}
+
+impl<'self> Cache {
+ fn generics(&mut self, generics: &clean::Generics) {
+ for typ in generics.type_params.iter() {
+ self.typarams.insert(typ.id, typ.name.clone());
+ }
+ }
+}
+
+impl Context {
+ fn recurse<T>(&mut self, s: ~str, f: &fn(&mut Context) -> T) -> T {
+ // Recurse in the directory structure and change the "root path" to make
+ // sure it always points to the top (relatively)
+ if s.len() == 0 {
+ fail2!("what {:?}", self);
+ }
+ let next = self.dst.push(s);
+ let prev = util::replace(&mut self.dst, next);
+ self.root_path.push_str("../");
+ self.current.push(s);
+
+ mkdir(&self.dst);
+ let ret = f(self);
+
+ // Go back to where we were at
+ self.dst = prev;
+ let len = self.root_path.len();
+ self.root_path.truncate(len - 3);
+ self.current.pop();
+
+ return ret;
+ }
+
+ /// Processes
+ fn crate(self, mut crate: clean::Crate, cache: Cache) {
+ enum Work {
+ Die,
+ Process(Context, clean::Item),
+ }
+ enum Progress { JobNew, JobDone }
+ static WORKERS: int = 10;
+
+ let mut item = match crate.module.take() {
+ Some(i) => i,
+ None => return
+ };
+ item.name = Some(crate.name);
+
+ let (port, chan) = comm::stream::<Work>();
+ let port = SharedPort::new(port);
+ let chan = SharedChan::new(chan);
+ let (prog_port, prog_chan) = comm::stream();
+ let prog_chan = SharedChan::new(prog_chan);
+ let cache = RWArc::new(cache);
+
+ for i in range(0, WORKERS) {
+ let port = port.clone();
+ let chan = chan.clone();
+ let prog_chan = prog_chan.clone();
+
+ let mut task = task::task();
+ task.unlinked(); // we kill things manually
+ task.name(format!("worker{}", i));
+ do task.spawn_with(cache.clone()) |cache| {
+ local_data::set(cache_key, cache);
+ loop {
+ match port.recv() {
+ Process(cx, item) => {
+ let mut cx = cx;
+ let item = Cell::new(item);
+ do (|| {
+ do cx.item(item.take()) |cx, item| {
+ prog_chan.send(JobNew);
+ chan.send(Process(cx.clone(), item));
+ }
+ }).finally {
+ // If we fail, everything else should still get
+ // completed
+ prog_chan.send(JobDone);
+ }
+ }
+ Die => break,
+ }
+ }
+ }
+ }
+
+ let watcher_chan = chan.clone();
+ let (done_port, done_chan) = comm::stream();
+ do task::spawn {
+ let mut jobs = 0;
+ loop {
+ match prog_port.recv() {
+ JobNew => jobs += 1,
+ JobDone => jobs -= 1,
+ }
+
+ if jobs == 0 { break }
+ }
+
+ for _ in range(0, WORKERS) {
+ watcher_chan.send(Die);
+ }
+ done_chan.send(());
+ }
+
+ prog_chan.send(JobNew);
+ chan.send(Process(self, item));
+ done_port.recv();
+ }
+
+ fn item(&mut self, item: clean::Item, f: &fn(&mut Context, clean::Item)) {
+ fn render(w: io::file::FileWriter, cx: &mut Context, it: &clean::Item,
+ pushname: bool) {
+ // A little unfortunate that this is done like this, but it sure
+ // does make formatting *a lot* nicer.
+ local_data::set(current_location_key, cx.current.clone());
+
+ let mut title = cx.current.connect("::");
+ if pushname {
+ if title.len() > 0 { title.push_str("::"); }
+ title.push_str(*it.name.get_ref());
+ }
+ title.push_str(" - Rust");
+ let page = layout::Page {
+ ty: shortty(it),
+ root_path: cx.root_path,
+ title: title,
+ };
+
+ // We have a huge number of calls to write, so try to alleviate some
+ // of the pain by using a buffered writer instead of invoking the
+ // write sycall all the time.
+ let mut writer = BufferedWriter::new(w);
+ layout::render(&mut writer as &mut io::Writer, &cx.layout, &page,
+ &Sidebar{ cx: cx, item: it },
+ &Item{ cx: cx, item: it });
+ writer.flush();
+ }
+
+ match item.inner {
+ clean::ModuleItem(*) => {
+ let name = item.name.get_ref().to_owned();
+ let item = Cell::new(item);
+ do self.recurse(name) |this| {
+ let item = item.take();
+ let dst = this.dst.push("index.html");
+ let writer = dst.open_writer(io::CreateOrTruncate);
+ render(writer.unwrap(), this, &item, false);
+
+ let m = match item.inner {
+ clean::ModuleItem(m) => m,
+ _ => unreachable!()
+ };
+ this.sidebar = build_sidebar(&m);
+ for item in m.items.move_iter() {
+ f(this, item);
+ }
+ }
+ }
+ _ if item.name.is_some() => {
+ let dst = self.dst.push(item_path(&item));
+ let writer = dst.open_writer(io::CreateOrTruncate);
+ render(writer.unwrap(), self, &item, true);
+ }
+ _ => {}
+ }
+ }
+}
+
+fn shortty(item: &clean::Item) -> &'static str {
+ match item.inner {
+ clean::ModuleItem(*) => "mod",
+ clean::StructItem(*) => "struct",
+ clean::EnumItem(*) => "enum",
+ clean::FunctionItem(*) => "fn",
+ clean::TypedefItem(*) => "typedef",
+ clean::StaticItem(*) => "static",
+ clean::TraitItem(*) => "trait",
+ clean::ImplItem(*) => "impl",
+ clean::ViewItemItem(*) => "viewitem",
+ clean::TyMethodItem(*) => "tymethod",
+ clean::MethodItem(*) => "method",
+ clean::StructFieldItem(*) => "structfield",
+ clean::VariantItem(*) => "variant",
+ }
+}
+
+impl<'self> Item<'self> {
+ fn ismodule(&self) -> bool {
+ match self.item.inner {
+ clean::ModuleItem(*) => true, _ => false
+ }
+ }
+}
+
+impl<'self> fmt::Default for Item<'self> {
+ fn fmt(it: &Item<'self>, fmt: &mut fmt::Formatter) {
+ // Write the breadcrumb trail header for the top
+ write!(fmt.buf, "<h1 class='fqn'>");
+ match it.item.inner {
+ clean::ModuleItem(*) => write!(fmt.buf, "Module "),
+ clean::FunctionItem(*) => write!(fmt.buf, "Function "),
+ clean::TraitItem(*) => write!(fmt.buf, "Trait "),
+ clean::StructItem(*) => write!(fmt.buf, "Struct "),
+ clean::EnumItem(*) => write!(fmt.buf, "Enum "),
+ _ => {}
+ }
+ let cur = it.cx.current.as_slice();
+ let amt = if it.ismodule() { cur.len() - 1 } else { cur.len() };
+ for (i, component) in cur.iter().enumerate().take(amt) {
+ let mut trail = ~"";
+ for _ in range(0, cur.len() - i - 1) {
+ trail.push_str("../");
+ }
+ write!(fmt.buf, "<a href='{}index.html'>{}</a>::",
+ trail, component.as_slice());
+ }
+ write!(fmt.buf, "<a class='{}' href=''>{}</a></h1>",
+ shortty(it.item), it.item.name.get_ref().as_slice());
+
+ match it.item.inner {
+ clean::ModuleItem(ref m) => item_module(fmt.buf, it.cx,
+ it.item, m.items),
+ clean::FunctionItem(ref f) => item_function(fmt.buf, it.item, f),
+ clean::TraitItem(ref t) => item_trait(fmt.buf, it.item, t),
+ clean::StructItem(ref s) => item_struct(fmt.buf, it.item, s),
+ clean::EnumItem(ref e) => item_enum(fmt.buf, it.item, e),
+ clean::TypedefItem(ref t) => item_typedef(fmt.buf, it.item, t),
+ _ => {}
+ }
+ }
+}
+
+fn item_path(item: &clean::Item) -> ~str {
+ match item.inner {
+ clean::ModuleItem(*) => *item.name.get_ref() + "/index.html",
+ _ => shortty(item) + "." + *item.name.get_ref() + ".html"
+ }
+}
+
+fn full_path(cx: &Context, item: &clean::Item) -> ~str {
+ let mut s = cx.current.connect("::");
+ s.push_str("::");
+ s.push_str(item.name.get_ref().as_slice());
+ return s;
+}
+
+fn blank<'a>(s: Option<&'a str>) -> &'a str {
+ match s {
+ Some(s) => s,
+ None => ""
+ }
+}
+
+fn shorter<'a>(s: Option<&'a str>) -> &'a str {
+ match s {
+ Some(s) => match s.find_str("\n\n") {
+ Some(pos) => s.slice_to(pos),
+ None => s,
+ },
+ None => ""
+ }
+}
+
+fn document(w: &mut io::Writer, item: &clean::Item) {
+ match item.doc_value() {
+ Some(s) => {
+ write!(w, "<div class='docblock'>{}</div>", Markdown(s));
+ }
+ None => {}
+ }
+}
+
+fn item_module(w: &mut io::Writer, cx: &Context,
+ item: &clean::Item, items: &[clean::Item]) {
+ document(w, item);
+ let mut indices = vec::from_fn(items.len(), |i| i);
+
+ fn lt(i1: &clean::Item, i2: &clean::Item) -> bool {
+ if shortty(i1) == shortty(i2) {
+ return i1.name < i2.name;
+ }
+ match (&i1.inner, &i2.inner) {
+ (&clean::ViewItemItem(*), _) => true,
+ (_, &clean::ViewItemItem(*)) => false,
+ (&clean::ModuleItem(*), _) => true,
+ (_, &clean::ModuleItem(*)) => false,
+ (&clean::StructItem(*), _) => true,
+ (_, &clean::StructItem(*)) => false,
+ (&clean::EnumItem(*), _) => true,
+ (_, &clean::EnumItem(*)) => false,
+ (&clean::StaticItem(*), _) => true,
+ (_, &clean::StaticItem(*)) => false,
+ (&clean::TraitItem(*), _) => true,
+ (_, &clean::TraitItem(*)) => false,
+ (&clean::FunctionItem(*), _) => true,
+ (_, &clean::FunctionItem(*)) => false,
+ (&clean::TypedefItem(*), _) => true,
+ (_, &clean::TypedefItem(*)) => false,
+ _ => false,
+ }
+ }
+
+ do sort::quick_sort(indices) |&i1, &i2| {
+ lt(&items[i1], &items[i2])
+ }
+
+ let mut curty = "";
+ for &idx in indices.iter() {
+ let myitem = &items[idx];
+ if myitem.name.is_none() { loop }
+
+ let myty = shortty(myitem);
+ if myty != curty {
+ if curty != "" {
+ write!(w, "</table>");
+ }
+ curty = myty;
+ write!(w, "<h2>{}</h2>\n<table>", match myitem.inner {
+ clean::ModuleItem(*) => "Modules",
+ clean::StructItem(*) => "Structs",
+ clean::EnumItem(*) => "Enums",
+ clean::FunctionItem(*) => "Functions",
+ clean::TypedefItem(*) => "Type Definitions",
+ clean::StaticItem(*) => "Statics",
+ clean::TraitItem(*) => "Traits",
+ clean::ImplItem(*) => "Implementations",
+ clean::ViewItemItem(*) => "Reexports",
+ clean::TyMethodItem(*) => "Type Methods",
+ clean::MethodItem(*) => "Methods",
+ clean::StructFieldItem(*) => "Struct Fields",
+ clean::VariantItem(*) => "Variants",
+ });
+ }
+
+ match myitem.inner {
+ clean::StaticItem(ref s) => {
+ struct Initializer<'self>(&'self str);
+ impl<'self> fmt::Default for Initializer<'self> {
+ fn fmt(s: &Initializer<'self>, f: &mut fmt::Formatter) {
+ let tag = if s.contains("\n") { "pre" } else { "code" };
+ write!(f.buf, "<{tag}>{}</{tag}>",
+ s.as_slice(), tag=tag);
+ }
+ }
+
+ write!(w, "
+ <tr>
+ <td><code>{}: {} = </code>{}</td>
+ <td class='docblock'>{} </td>
+ </tr>
+ ",
+ *myitem.name.get_ref(),
+ s.type_,
+ Initializer(s.expr),
+ Markdown(blank(myitem.doc_value())));
+ }
+
+ _ => {
+ write!(w, "
+ <tr>
+ <td><a class='{class}' href='{href}'
+ title='{title}'>{}</a></td>
+ <td class='docblock short'>{}</td>
+ </tr>
+ ",
+ *myitem.name.get_ref(),
+ Markdown(shorter(myitem.doc_value())),
+ class = shortty(myitem),
+ href = item_path(myitem),
+ title = full_path(cx, myitem));
+ }
+ }
+ }
+ write!(w, "</table>");
+}
+
+fn item_function(w: &mut io::Writer, it: &clean::Item, f: &clean::Function) {
+ write!(w, "<pre class='fn'>{vis}fn {name}{generics}{decl}</pre>",
+ vis = VisSpace(it.visibility),
+ name = it.name.get_ref().as_slice(),
+ generics = f.generics,
+ decl = f.decl);
+ document(w, it);
+}
+
+fn item_trait(w: &mut io::Writer, it: &clean::Item, t: &clean::Trait) {
+ let mut parents = ~"";
+ if t.parents.len() > 0 {
+ parents.push_str(": ");
+ for (i, p) in t.parents.iter().enumerate() {
+ if i > 0 { parents.push_str(" + "); }
+ parents.push_str(format!("{}", *p));
+ }
+ }
+
+ // Output the trait definition
+ write!(w, "<pre class='trait'>{}trait {}{}{} ",
+ VisSpace(it.visibility),
+ it.name.get_ref().as_slice(),
+ t.generics,
+ parents);
+ let required = t.methods.iter().filter(|m| m.is_req()).to_owned_vec();
+ let provided = t.methods.iter().filter(|m| !m.is_req()).to_owned_vec();
+
+ if t.methods.len() == 0 {
+ write!(w, "\\{ \\}");
+ } else {
+ write!(w, "\\{\n");
+ for m in required.iter() {
+ write!(w, " ");
+ render_method(w, m.item(), true);
+ write!(w, ";\n");
+ }
+ if required.len() > 0 && provided.len() > 0 {
+ w.write("\n".as_bytes());
+ }
+ for m in provided.iter() {
+ write!(w, " ");
+ render_method(w, m.item(), true);
+ write!(w, " \\{ ... \\}\n");
+ }
+ write!(w, "\\}");
+ }
+ write!(w, "</pre>");
+
+ // Trait documentation
+ document(w, it);
+
+ fn meth(w: &mut io::Writer, m: &clean::TraitMethod) {
+ write!(w, "<h3 id='fn.{}' class='method'><code>",
+ *m.item().name.get_ref());
+ render_method(w, m.item(), false);
+ write!(w, "</code></h3>");
+ document(w, m.item());
+ }
+
+ // Output the documentation for each function individually
+ if required.len() > 0 {
+ write!(w, "
+ <h2 id='required-methods'>Required Methods</h2>
+ <div class='methods'>
+ ");
+ for m in required.iter() {
+ meth(w, *m);
+ }
+ write!(w, "</div>");
+ }
+ if provided.len() > 0 {
+ write!(w, "
+ <h2 id='provided-methods'>Provided Methods</h2>
+ <div class='methods'>
+ ");
+ for m in provided.iter() {
+ meth(w, *m);
+ }
+ write!(w, "</div>");
+ }
+
+ do local_data::get(cache_key) |cache| {
+ do cache.unwrap().read |cache| {
+ match cache.implementors.find(&it.id) {
+ Some(implementors) => {
+ write!(w, "
+ <h2 id='implementors'>Implementors</h2>
+ <ul class='item-list'>
+ ");
+ for i in implementors.iter() {
+ match *i {
+ PathType(ref ty) => {
+ write!(w, "<li><code>{}</code></li>", *ty);
+ }
+ OtherType(ref generics, ref trait_, ref for_) => {
+ write!(w, "<li><code>impl{} {} for {}</code></li>",
+ *generics, *trait_, *for_);
+ }
+ }
+ }
+ write!(w, "</ul>");
+ }
+ None => {}
+ }
+ }
+ }
+}
+
+fn render_method(w: &mut io::Writer, meth: &clean::Item, withlink: bool) {
+ fn fun(w: &mut io::Writer, it: &clean::Item, purity: ast::purity,
+ g: &clean::Generics, selfty: &clean::SelfTy, d: &clean::FnDecl,
+ withlink: bool) {
+ write!(w, "{}fn {withlink, select,
+ true{<a href='\\#fn.{name}'>{name}</a>}
+ other{{name}}
+ }{generics}{decl}",
+ match purity {
+ ast::unsafe_fn => "unsafe ",
+ _ => "",
+ },
+ name = it.name.get_ref().as_slice(),
+ generics = *g,
+ decl = Method(selfty, d),
+ withlink = if withlink {"true"} else {"false"});
+ }
+ match meth.inner {
+ clean::TyMethodItem(ref m) => {
+ fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink);
+ }
+ clean::MethodItem(ref m) => {
+ fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink);
+ }
+ _ => unreachable!()
+ }
+}
+
+fn item_struct(w: &mut io::Writer, it: &clean::Item, s: &clean::Struct) {
+ write!(w, "<pre class='struct'>");
+ render_struct(w, it, Some(&s.generics), s.struct_type, s.fields, "");
+ write!(w, "</pre>");
+
+ document(w, it);
+ render_methods(w, it);
+}
+
+fn item_enum(w: &mut io::Writer, it: &clean::Item, e: &clean::Enum) {
+ write!(w, "<pre class='enum'>{}enum {}{}",
+ VisSpace(it.visibility),
+ it.name.get_ref().as_slice(),
+ e.generics);
+ if e.variants.len() == 0 {
+ write!(w, " \\{\\}");
+ } else {
+ write!(w, " \\{\n");
+ for v in e.variants.iter() {
+ let name = v.name.get_ref().as_slice();
+ match v.inner {
+ clean::VariantItem(ref var) => {
+ match var.kind {
+ clean::CLikeVariant => write!(w, " {},\n", name),
+ clean::TupleVariant(ref tys) => {
+ write!(w, " {}(", name);
+ for (i, ty) in tys.iter().enumerate() {
+ if i > 0 { write!(w, ", ") }
+ write!(w, "{}", *ty);
+ }
+ write!(w, "),\n");
+ }
+ clean::StructVariant(ref s) => {
+ render_struct(w, v, None, s.struct_type, s.fields,
+ " ");
+ }
+ }
+ }
+ _ => unreachable!()
+ }
+ }
+ write!(w, "\\}");
+ }
+ write!(w, "</pre>");
+
+ document(w, it);
+ render_methods(w, it);
+}
+
+fn render_struct(w: &mut io::Writer, it: &clean::Item,
+ g: Option<&clean::Generics>,
+ ty: doctree::StructType,
+ fields: &[clean::Item],
+ tab: &str) {
+ write!(w, "{}struct {}",
+ VisSpace(it.visibility),
+ it.name.get_ref().as_slice());
+ match g {
+ Some(g) => write!(w, "{}", *g),
+ None => {}
+ }
+ match ty {
+ doctree::Plain => {
+ write!(w, " \\{\n");
+ for field in fields.iter() {
+ match field.inner {
+ clean::StructFieldItem(ref ty) => {
+ write!(w, " {}{}: {},\n{}",
+ VisSpace(field.visibility),
+ field.name.get_ref().as_slice(),
+ ty.type_,
+ tab);
+ }
+ _ => unreachable!()
+ }
+ }
+ write!(w, "\\}");
+ }
+ doctree::Tuple | doctree::Newtype => {
+ write!(w, "(");
+ for (i, field) in fields.iter().enumerate() {
+ if i > 0 { write!(w, ", ") }
+ match field.inner {
+ clean::StructFieldItem(ref field) => {
+ write!(w, "{}", field.type_);
+ }
+ _ => unreachable!()
+ }
+ }
+ write!(w, ");");
+ }
+ doctree::Unit => { write!(w, ";"); }
+ }
+}
+
+fn render_methods(w: &mut io::Writer, it: &clean::Item) {
+ do local_data::get(cache_key) |cache| {
+ let cache = cache.unwrap();
+ do cache.read |c| {
+ match c.impls.find(&it.id) {
+ Some(v) => {
+ let mut non_trait = v.iter().filter(|i| i.trait_.is_none());
+ let non_trait = non_trait.to_owned_vec();
+ let mut traits = v.iter().filter(|i| i.trait_.is_some());
+ let traits = traits.to_owned_vec();
+
+ if non_trait.len() > 0 {
+ write!(w, "<h2 id='methods'>Methods</h2>");
+ for &i in non_trait.iter() {
+ render_impl(w, i);
+ }
+ }
+ if traits.len() > 0 {
+ write!(w, "<h2 id='implementations'>Trait \
+ Implementations</h2>");
+ for &i in traits.iter() {
+ render_impl(w, i);
+ }
+ }
+ }
+ None => {}
+ }
+ }
+ }
+}
+
+fn render_impl(w: &mut io::Writer, i: &clean::Impl) {
+ write!(w, "<h3 class='impl'><code>impl{} ", i.generics);
+ let trait_id = match i.trait_ {
+ Some(ref ty) => {
+ write!(w, "{} for ", *ty);
+ match *ty {
+ clean::ResolvedPath { id, _ } => Some(id),
+ _ => None,
+ }
+ }
+ None => None
+ };
+ write!(w, "{}</code></h3>", i.for_);
+ write!(w, "<div class='methods'>");
+ for meth in i.methods.iter() {
+ write!(w, "<h4 id='fn.{}' class='method'><code>",
+ *meth.name.get_ref());
+ render_method(w, meth, false);
+ write!(w, "</code></h4>\n");
+ match meth.doc_value() {
+ Some(s) => {
+ write!(w, "<div class='docblock'>{}</div>", Markdown(s));
+ loop
+ }
+ None => {}
+ }
+
+ // No documentation? Attempt to slurp in the trait's documentation
+ let trait_id = match trait_id { Some(id) => id, None => loop };
+ do local_data::get(cache_key) |cache| {
+ do cache.unwrap().read |cache| {
+ let name = meth.name.get_ref().as_slice();
+ match cache.traits.find(&trait_id) {
+ Some(m) => {
+ match m.find_equiv(&name) {
+ Some(s) => {
+ write!(w, "<div class='docblock'>{}</div>",
+ Markdown(s.as_slice()));
+ }
+ None => {}
+ }
+ }
+ None => {}
+ }
+ }
+ }
+ }
+ write!(w, "</div>");
+}
+
+fn item_typedef(w: &mut io::Writer, it: &clean::Item, t: &clean::Typedef) {
+ write!(w, "<pre class='typedef'>type {}{} = {};</pre>",
+ it.name.get_ref().as_slice(),
+ t.generics,
+ t.type_);
+
+ document(w, it);
+}
+
+impl<'self> fmt::Default for Sidebar<'self> {
+ fn fmt(s: &Sidebar<'self>, fmt: &mut fmt::Formatter) {
+ let cx = s.cx;
+ let it = s.item;
+ write!(fmt.buf, "<p class='location'>");
+ let len = cx.current.len() - if it.is_mod() {1} else {0};
+ for (i, name) in cx.current.iter().take(len).enumerate() {
+ if i > 0 { write!(fmt.buf, "&\\#8203;::") }
+ write!(fmt.buf, "<a href='{}index.html'>{}</a>",
+ cx.root_path.slice_to((cx.current.len() - i - 1) * 3), *name);
+ }
+ write!(fmt.buf, "</p>");
+
+ fn block(w: &mut io::Writer, short: &str, longty: &str,
+ cur: &clean::Item, cx: &Context) {
+ let items = match cx.sidebar.find_equiv(&short) {
+ Some(items) => items.as_slice(),
+ None => return
+ };
+ write!(w, "<div class='block {}'><h2>{}</h2>", short, longty);
+ for item in items.iter() {
+ let class = if cur.name.get_ref() == item &&
+ short == shortty(cur) { "current" } else { "" };
+ write!(w, "<a class='{ty} {class}' href='{curty, select,
+ mod{../}
+ other{}
+ }{ty, select,
+ mod{{name}/index.html}
+ other{#.{name}.html}
+ }'>{name}</a><br/>",
+ ty = short,
+ class = class,
+ curty = shortty(cur),
+ name = item.as_slice());
+ }
+ write!(w, "</div>");
+ }
+
+ block(fmt.buf, "mod", "Modules", it, cx);
+ block(fmt.buf, "struct", "Structs", it, cx);
+ block(fmt.buf, "enum", "Enums", it, cx);
+ block(fmt.buf, "trait", "Traits", it, cx);
+ block(fmt.buf, "fn", "Functions", it, cx);
+ }
+}
+
+fn build_sidebar(m: &clean::Module) -> HashMap<~str, ~[~str]> {
+ let mut map = HashMap::new();
+ for item in m.items.iter() {
+ let short = shortty(item);
+ let myname = match item.name {
+ None => loop,
+ Some(ref s) => s.to_owned(),
+ };
+ let v = map.find_or_insert_with(short.to_owned(), |_| ~[]);
+ v.push(myname);
+ }
+
+ for (_, items) in map.mut_iter() {
+ sort::quick_sort(*items, |i1, i2| i1 < i2);
+ }
+ return map;
+}
--- /dev/null
+/*! jQuery v2.0.3 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
+//@ sourceMappingURL=jquery-2.0.3.min.map
+*/
+(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],p="2.0.3",f=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:p,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return f.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,p,f,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=st(),k=st(),N=st(),E=!1,S=function(e,t){return e===t?(E=!0,0):0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],q=L.pop,H=L.push,O=L.push,F=L.slice,P=L.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",W="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",$=W.replace("w","w#"),B="\\["+M+"*("+W+")"+M+"*(?:([*^$|!~]?=)"+M+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+$+")|)|)"+M+"*\\]",I=":("+W+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+B.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=RegExp("^"+M+"*,"+M+"*"),X=RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=RegExp(M+"*[+~]"),Y=RegExp("="+M+"*([^\\]'\"]*)"+M+"*\\]","g"),V=RegExp(I),G=RegExp("^"+$+"$"),J={ID:RegExp("^#("+W+")"),CLASS:RegExp("^\\.("+W+")"),TAG:RegExp("^("+W.replace("w","w*")+")"),ATTR:RegExp("^"+B),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:RegExp("^(?:"+R+")$","i"),needsContext:RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Q=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Z=/^(?:input|select|textarea|button)$/i,et=/^h\d$/i,tt=/'|\\/g,nt=RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),rt=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{O.apply(L=F.call(b.childNodes),b.childNodes),L[b.childNodes.length].nodeType}catch(it){O={apply:L.length?function(e,t){H.apply(e,F.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function ot(e,t,r,i){var o,s,a,u,l,f,g,m,x,w;if((t?t.ownerDocument||t:b)!==p&&c(t),t=t||p,r=r||[],!e||"string"!=typeof e)return r;if(1!==(u=t.nodeType)&&9!==u)return[];if(h&&!i){if(o=K.exec(e))if(a=o[1]){if(9===u){if(s=t.getElementById(a),!s||!s.parentNode)return r;if(s.id===a)return r.push(s),r}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(a))&&y(t,s)&&s.id===a)return r.push(s),r}else{if(o[2])return O.apply(r,t.getElementsByTagName(e)),r;if((a=o[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(a)),r}if(n.qsa&&(!d||!d.test(e))){if(m=g=v,x=t,w=9===u&&e,1===u&&"object"!==t.nodeName.toLowerCase()){f=gt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=f.length;while(l--)f[l]=m+mt(f[l]);x=U.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,r,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function at(e){return e[v]=!0,e}function ut(e){var t=p.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function lt(e,t){var n=e.split("|"),r=e.length;while(r--)i.attrHandle[n[r]]=t}function ct(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return at(function(t){return t=+t,at(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}s=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},n=ot.support={},c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:b,r=t.defaultView;return t!==p&&9===t.nodeType&&t.documentElement?(p=t,f=t.documentElement,h=!s(t),r&&r.attachEvent&&r!==r.top&&r.attachEvent("onbeforeunload",function(){c()}),n.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ut(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),n.getById=ut(function(e){return f.appendChild(e).id=v,!t.getElementsByName||!t.getElementsByName(v).length}),n.getById?(i.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){return e.getAttribute("id")===t}}):(delete i.find.ID,i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=n.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.CLASS=n.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&h?t.getElementsByClassName(e):undefined},g=[],d=[],(n.qsa=Q.test(t.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||d.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll(":checked").length||d.push(":checked")}),ut(function(e){var n=t.createElement("input");n.setAttribute("type","hidden"),e.appendChild(n).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&d.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||d.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),d.push(",.*:")})),(n.matchesSelector=Q.test(m=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&ut(function(e){n.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",I)}),d=d.length&&RegExp(d.join("|")),g=g.length&&RegExp(g.join("|")),y=Q.test(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},S=f.compareDocumentPosition?function(e,r){if(e===r)return E=!0,0;var i=r.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(r);return i?1&i||!n.sortDetached&&r.compareDocumentPosition(e)===i?e===t||y(b,e)?-1:r===t||y(b,r)?1:l?P.call(l,e)-P.call(l,r):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],u=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:l?P.call(l,e)-P.call(l,n):0;if(o===s)return ct(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)u.unshift(r);while(a[i]===u[i])i++;return i?ct(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):p},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Y,"='$1']"),!(!n.matchesSelector||!h||g&&g.test(t)||d&&d.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return ot(t,p,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==p&&c(e);var r=i.attrHandle[t.toLowerCase()],o=r&&A.call(i.attrHandle,t.toLowerCase())?r(e,t,!h):undefined;return o===undefined?n.attributes||!h?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null:o},ot.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ot.uniqueSort=function(e){var t,r=[],i=0,o=0;if(E=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(S),E){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return e},o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=ot.selectors={cacheLength:50,createPseudo:at,match:J,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(nt,rt),e[3]=(e[4]||e[5]||"").replace(nt,rt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ot.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ot.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return J.CHILD.test(e[0])?null:(e[3]&&e[4]!==undefined?e[2]=e[4]:n&&V.test(n)&&(t=gt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(nt,rt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){p=t;while(p=p[g])if(a?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[v]||(m[v]={}),l=c[e]||[],h=l[0]===w&&l[1],f=l[0]===w&&l[2],p=h&&m.childNodes[h];while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[w,h,f];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)f=l[1];else while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if((a?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(x&&((p[v]||(p[v]={}))[e]=[w,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);return r[v]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?at(function(e,n){var i,o=r(e,t),s=o.length;while(s--)i=P.call(e,o[s]),e[i]=!(n[i]=o[s])}):function(e){return r(e,0,n)}):r}},pseudos:{not:at(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?at(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:at(function(e){return function(t){return ot(e,t).length>0}}),contains:at(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:at(function(e){return G.test(e||"")||ot.error("unsupported lang: "+e),e=e.replace(nt,rt).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return et.test(e.nodeName)},input:function(e){return Z.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},i.pseudos.nth=i.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=pt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=ft(t);function dt(){}dt.prototype=i.filters=i.pseudos,i.setFilters=new dt;function gt(e,t){var n,r,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=i.preFilter;while(a){(!n||(r=_.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),u.push(o=[])),n=!1,(r=X.exec(a))&&(n=r.shift(),o.push({value:n,type:r[0].replace(z," ")}),a=a.slice(n.length));for(s in i.filter)!(r=J[s].exec(a))||l[s]&&!(r=l[s](r))||(n=r.shift(),o.push({value:n,type:s,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ot.error(e):k(e,u).slice(0)}function mt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function yt(e,t,n){var i=t.dir,o=n&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,a){var u,l,c,p=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[v]||(t[v]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function vt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function bt(e,t,n,r,i,o){return r&&!r[v]&&(r=bt(r)),i&&!i[v]&&(i=bt(i,o)),at(function(o,s,a,u){var l,c,p,f=[],h=[],d=s.length,g=o||Ct(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:xt(g,f,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=xt(y,h),r(l,[],a,u),c=l.length;while(c--)(p=l[c])&&(y[h[c]]=!(m[h[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?P.call(o,p):f[c])>-1&&(o[l]=!(s[l]=p))}}else y=xt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function wt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=yt(function(e){return e===t},a,!0),p=yt(function(e){return P.call(t,e)>-1},a,!0),f=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])f=[yt(vt(f),n)];else{if(n=i.filter[e[l].type].apply(null,e[l].matches),n[v]){for(r=++l;o>r;r++)if(i.relative[e[r].type])break;return bt(l>1&&vt(f),l>1&&mt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&wt(e.slice(l,r)),o>r&&wt(e=e.slice(r)),o>r&&mt(e))}f.push(n)}return vt(f)}function Tt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,f,h){var d,g,m,y=[],v=0,x="0",b=a&&[],T=null!=h,C=u,k=a||s&&i.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(u=l!==p&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){f.push(d);break}T&&(w=N,r=++n)}o&&((d=!m&&d)&&v--,a&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,c);if(a){if(v>0)while(x--)b[x]||y[x]||(y[x]=q.call(f));y=xt(y)}O.apply(f,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(f)}return T&&(w=N,u=C),b};return o?at(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=gt(e)),n=t.length;while(n--)o=wt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Tt(i,r))}return o};function Ct(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function kt(e,t,r,o){var s,u,l,c,p,f=gt(e);if(!o&&1===f.length){if(u=f[0]=f[0].slice(0),u.length>2&&"ID"===(l=u[0]).type&&n.getById&&9===t.nodeType&&h&&i.relative[u[1].type]){if(t=(i.find.ID(l.matches[0].replace(nt,rt),t)||[])[0],!t)return r;e=e.slice(u.shift().value.length)}s=J.needsContext.test(e)?0:u.length;while(s--){if(l=u[s],i.relative[c=l.type])break;if((p=i.find[c])&&(o=p(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&mt(u),!e)return O.apply(r,o),r;break}}}return a(e,f)(o,t,!h,r,U.test(e)),r}n.sortStable=v.split("").sort(S).join("")===v,n.detectDuplicates=E,c(),n.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(p.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||lt("type|href|height|width",function(e,t,n){return n?undefined:e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||lt("value",function(e,t,n){return n||"input"!==e.nodeName.toLowerCase()?undefined:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||lt(R,function(e,t,n){var r;return n?undefined:(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===!0?t.toLowerCase():null}),x.find=ot,x.expr=ot.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ot.uniqueSort,x.text=ot.getText,x.isXMLDoc=ot.isXML,x.contains=ot.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(p){for(t=e.memory&&p,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(p[0],p[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!a||n&&!u||(t=t||[],t=[e,t.slice?t.slice():t],r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,q,H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))x.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){var r;return t===undefined||t&&"string"==typeof t&&n===undefined?(r=this.get(e,t),r!==undefined?r:this.get(e,x.camelCase(t))):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(t===undefined)this.cache[o]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):(i=x.camelCase(t),t in s?r=[t,i]:(r=i,r=r in s?[r]:r.match(w)||[])),n=r.length;while(n--)delete s[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}},L=new F,q=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||q.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return q.access(e,t,n)},_removeData:function(e,t){q.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!q.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.slice(5)),P(i,r,s[r]));q.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:H.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=q.get(e,t),n&&(!r||x.isArray(n)?r=q.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t)
+};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=q.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,i=0,o=x(this),s=e.match(w)||[];while(t=s[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,p,f,h,d,g,m,y=q.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(f=x.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=x.event.special[d]||{},p=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,f.setup&&f.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),f.add&&(f.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,p):h.push(p),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,p,f,h,d,g,m=q.hasData(e)&&q.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){p=x.event.special[h]||{},h=(r?p.delegateType:p.bindType)||h,f=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=f.length;while(o--)c=f[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(f.splice(o,1),c.selector&&f.delegateCount--,p.remove&&p.remove.call(e,c));s&&!f.length&&(p.teardown&&p.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,q.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,p,f,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),f=x.event.special[d]||{},i||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!i&&!f.noBubble&&!x.isWindow(r)){for(l=f.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:f.bindType||d,p=(q.get(a,"events")||{})[t.type]&&q.get(a,"handle"),p&&p.apply(a,n),p=c&&a[c],p&&x.acceptData(a)&&p.apply&&p.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||f._default&&f._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(q.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,s=e,a=this.fixHooks[i];a||(this.fixHooks[i]=a=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new x.Event(s),t=r.length;while(t--)n=r[t],e[n]=s[n];return e.target||(e.target=o),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,s):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=/^(?:parents|prev(?:Until|All))/,Q=x.expr.match.needsContext,K={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(et(this,e||[],!0))},filter:function(e){return this.pushStack(et(this,e||[],!1))},is:function(e){return!!et(this,"string"==typeof e&&Q.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],s=Q.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function Z(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return Z(e,"nextSibling")},prev:function(e){return Z(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return e.contentDocument||x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(K[e]||x.unique(i),J.test(e)&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function et(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,nt=/<([\w:]+)/,rt=/<|&#?\w+;/,it=/<(?:script|style|link)/i,ot=/^(?:checkbox|radio)$/i,st=/checked\s*(?:[^=]|=\s*.checked.)/i,at=/^$|\/(?:java|ecma)script/i,ut=/^true\/(.*)/,lt=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ct={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ct.optgroup=ct.option,ct.tbody=ct.tfoot=ct.colgroup=ct.caption=ct.thead,ct.th=ct.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(mt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&dt(mt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(mt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!ct[(nt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(tt,"<$1></$2>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(mt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=f.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,p=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&st.test(d))return this.each(function(r){var i=p.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(mt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,mt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,ht),l=0;s>l;l++)a=o[l],at.test(a.type||"")&&!q.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(lt,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=mt(a),o=mt(e),r=0,i=o.length;i>r;r++)yt(o[r],s[r]);if(t)if(n)for(o=o||mt(e),s=s||mt(a),r=0,i=o.length;i>r;r++)gt(o[r],s[r]);else gt(e,a);return s=mt(a,"script"),s.length>0&&dt(s,!u&&mt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,p=e.length,f=t.createDocumentFragment(),h=[];for(;p>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(rt.test(i)){o=o||f.appendChild(t.createElement("div")),s=(nt.exec(i)||["",""])[1].toLowerCase(),a=ct[s]||ct._default,o.innerHTML=a[1]+i.replace(tt,"<$1></$2>")+a[2],l=a[0];while(l--)o=o.lastChild;x.merge(h,o.childNodes),o=f.firstChild,o.textContent=""}else h.push(t.createTextNode(i));f.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(f.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return f},cleanData:function(e){var t,n,r,i,o,s,a=x.event.special,u=0;for(;(n=e[u])!==undefined;u++){if(F.accepts(n)&&(o=n[q.expando],o&&(t=q.cache[o]))){if(r=Object.keys(t.events||{}),r.length)for(s=0;(i=r[s])!==undefined;s++)a[i]?x.event.remove(n,i):x.removeEvent(n,i,t.handle);q.cache[o]&&delete q.cache[o]}delete L.cache[n[L.expando]]}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}});function pt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ht(e){var t=ut.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function dt(e,t){var n=e.length,r=0;for(;n>r;r++)q.set(e[r],"globalEval",!t||q.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(q.hasData(e)&&(o=q.access(e),s=q.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function mt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function yt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ot.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var vt,xt,bt=/^(none|table(?!-c[ea]).+)/,wt=/^margin/,Tt=RegExp("^("+b+")(.*)$","i"),Ct=RegExp("^("+b+")(?!px)[a-z%]+$","i"),kt=RegExp("^([+-])=("+b+")","i"),Nt={BODY:"block"},Et={position:"absolute",visibility:"hidden",display:"block"},St={letterSpacing:0,fontWeight:400},jt=["Top","Right","Bottom","Left"],Dt=["Webkit","O","Moz","ms"];function At(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Dt.length;while(i--)if(t=Dt[i]+n,t in e)return t;return r}function Lt(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function qt(t){return e.getComputedStyle(t,null)}function Ht(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=q.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=q.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&q.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=qt(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return Ht(this,!0)},hide:function(){return Ht(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Lt(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=vt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=At(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=kt.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=At(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=vt(e,t,r)),"normal"===i&&t in St&&(i=St[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),vt=function(e,t,n){var r,i,o,s=n||qt(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Ct.test(a)&&wt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ot(e,t,n){var r=Tt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ft(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+jt[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+jt[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+jt[o]+"Width",!0,i))):(s+=x.css(e,"padding"+jt[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+jt[o]+"Width",!0,i)));return s}function Pt(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=qt(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=vt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Ct.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ft(e,t,n||(s?"border":"content"),r,o)+"px"}function Rt(e){var t=o,n=Nt[e];return n||(n=Mt(e,t),"none"!==n&&n||(xt=(xt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(xt[0].contentWindow||xt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=Mt(e,t),xt.detach()),Nt[e]=n),n}function Mt(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,t){x.cssHooks[t]={get:function(e,n,r){return n?0===e.offsetWidth&&bt.test(x.css(e,"display"))?x.swap(e,Et,function(){return Pt(e,t,r)}):Pt(e,t,r):undefined},set:function(e,n,r){var i=r&&qt(e);return Ot(e,n,r?Ft(e,t,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,t){return t?x.swap(e,{display:"inline-block"},vt,[e,"marginRight"]):undefined}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,t){x.cssHooks[t]={get:function(e,n){return n?(n=vt(e,t),Ct.test(n)?x(e).position()[t]+"px":n):undefined}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+jt[r]+t]=o[r]||o[r-2]||o[0];return i}},wt.test(e)||(x.cssHooks[e+t].set=Ot)});var Wt=/%20/g,$t=/\[\]$/,Bt=/\r?\n/g,It=/^(?:submit|button|image|reset|file)$/i,zt=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&zt.test(this.nodeName)&&!It.test(e)&&(this.checked||!ot.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(Bt,"\r\n")}}):{name:t.name,value:n.replace(Bt,"\r\n")}}).get()}}),x.param=function(e,t){var n,r=[],i=function(e,t){t=x.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(t===undefined&&(t=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){i(this.name,this.value)});else for(n in e)_t(n,e[n],t,i);return r.join("&").replace(Wt,"+")};function _t(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||$t.test(e)?r(e,i):_t(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)_t(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)
+},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var Xt,Ut,Yt=x.now(),Vt=/\?/,Gt=/#.*$/,Jt=/([?&])_=[^&]*/,Qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Kt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Zt=/^(?:GET|HEAD)$/,en=/^\/\//,tn=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,nn=x.fn.load,rn={},on={},sn="*/".concat("*");try{Ut=i.href}catch(an){Ut=o.createElement("a"),Ut.href="",Ut=Ut.href}Xt=tn.exec(Ut.toLowerCase())||[];function un(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function ln(e,t,n,r){var i={},o=e===on;function s(a){var u;return i[a]=!0,x.each(e[a]||[],function(e,a){var l=a(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):undefined:(t.dataTypes.unshift(l),s(l),!1)}),u}return s(t.dataTypes[0])||!i["*"]&&s("*")}function cn(e,t){var n,r,i=x.ajaxSettings.flatOptions||{};for(n in t)t[n]!==undefined&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,t,n){if("string"!=typeof e&&nn)return nn.apply(this,arguments);var r,i,o,s=this,a=e.indexOf(" ");return a>=0&&(r=e.slice(a),e=e.slice(0,a)),x.isFunction(t)?(n=t,t=undefined):t&&"object"==typeof t&&(i="POST"),s.length>0&&x.ajax({url:e,type:i,dataType:"html",data:t}).done(function(e){o=arguments,s.html(r?x("<div>").append(x.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ut,type:"GET",isLocal:Kt.test(Xt[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":sn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?cn(cn(e,x.ajaxSettings),t):cn(x.ajaxSettings,e)},ajaxPrefilter:un(rn),ajaxTransport:un(on),ajax:function(e,t){"object"==typeof e&&(t=e,e=undefined),t=t||{};var n,r,i,o,s,a,u,l,c=x.ajaxSetup({},t),p=c.context||c,f=c.context&&(p.nodeType||p.jquery)?x(p):x.event,h=x.Deferred(),d=x.Callbacks("once memory"),g=c.statusCode||{},m={},y={},v=0,b="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===v){if(!o){o={};while(t=Qt.exec(i))o[t[1].toLowerCase()]=t[2]}t=o[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===v?i:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return v||(e=y[n]=y[n]||e,m[e]=t),this},overrideMimeType:function(e){return v||(c.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>v)for(t in e)g[t]=[g[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||b;return n&&n.abort(t),k(0,t),this}};if(h.promise(T).complete=d.add,T.success=T.done,T.error=T.fail,c.url=((e||c.url||Ut)+"").replace(Gt,"").replace(en,Xt[1]+"//"),c.type=t.method||t.type||c.method||c.type,c.dataTypes=x.trim(c.dataType||"*").toLowerCase().match(w)||[""],null==c.crossDomain&&(a=tn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===Xt[1]&&a[2]===Xt[2]&&(a[3]||("http:"===a[1]?"80":"443"))===(Xt[3]||("http:"===Xt[1]?"80":"443")))),c.data&&c.processData&&"string"!=typeof c.data&&(c.data=x.param(c.data,c.traditional)),ln(rn,c,t,T),2===v)return T;u=c.global,u&&0===x.active++&&x.event.trigger("ajaxStart"),c.type=c.type.toUpperCase(),c.hasContent=!Zt.test(c.type),r=c.url,c.hasContent||(c.data&&(r=c.url+=(Vt.test(r)?"&":"?")+c.data,delete c.data),c.cache===!1&&(c.url=Jt.test(r)?r.replace(Jt,"$1_="+Yt++):r+(Vt.test(r)?"&":"?")+"_="+Yt++)),c.ifModified&&(x.lastModified[r]&&T.setRequestHeader("If-Modified-Since",x.lastModified[r]),x.etag[r]&&T.setRequestHeader("If-None-Match",x.etag[r])),(c.data&&c.hasContent&&c.contentType!==!1||t.contentType)&&T.setRequestHeader("Content-Type",c.contentType),T.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+("*"!==c.dataTypes[0]?", "+sn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)T.setRequestHeader(l,c.headers[l]);if(c.beforeSend&&(c.beforeSend.call(p,T,c)===!1||2===v))return T.abort();b="abort";for(l in{success:1,error:1,complete:1})T[l](c[l]);if(n=ln(on,c,t,T)){T.readyState=1,u&&f.trigger("ajaxSend",[T,c]),c.async&&c.timeout>0&&(s=setTimeout(function(){T.abort("timeout")},c.timeout));try{v=1,n.send(m,k)}catch(C){if(!(2>v))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,t,o,a){var l,m,y,b,w,C=t;2!==v&&(v=2,s&&clearTimeout(s),n=undefined,i=a||"",T.readyState=e>0?4:0,l=e>=200&&300>e||304===e,o&&(b=pn(c,T,o)),b=fn(c,b,T,l),l?(c.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(x.lastModified[r]=w),w=T.getResponseHeader("etag"),w&&(x.etag[r]=w)),204===e||"HEAD"===c.type?C="nocontent":304===e?C="notmodified":(C=b.state,m=b.data,y=b.error,l=!y)):(y=C,(e||!C)&&(C="error",0>e&&(e=0))),T.status=e,T.statusText=(t||C)+"",l?h.resolveWith(p,[m,C,T]):h.rejectWith(p,[T,C,y]),T.statusCode(g),g=undefined,u&&f.trigger(l?"ajaxSuccess":"ajaxError",[T,c,l?m:y]),d.fireWith(p,[T,C]),u&&(f.trigger("ajaxComplete",[T,c]),--x.active||x.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,t){return x.get(e,undefined,t,"script")}}),x.each(["get","post"],function(e,t){x[t]=function(e,n,r,i){return x.isFunction(n)&&(i=i||r,r=n,n=undefined),x.ajax({url:e,type:t,dataType:i,data:n,success:r})}});function pn(e,t,n){var r,i,o,s,a=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),r===undefined&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in a)if(a[i]&&a[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}s||(s=i)}o=o||s}return o?(o!==u[0]&&u.unshift(o),n[o]):undefined}function fn(e,t,n,r){var i,o,s,a,u,l={},c=e.dataTypes.slice();if(c[1])for(s in e.converters)l[s.toLowerCase()]=e.converters[s];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(s=l[u+" "+o]||l["* "+o],!s)for(i in l)if(a=i.split(" "),a[1]===o&&(s=l[u+" "+a[0]]||l["* "+a[0]])){s===!0?s=l[i]:l[i]!==!0&&(o=a[0],c.unshift(a[1]));break}if(s!==!0)if(s&&e["throws"])t=s(t);else try{t=s(t)}catch(p){return{state:"parsererror",error:s?p:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===undefined&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),x.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(r,i){t=x("<script>").prop({async:!0,charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&i("error"===e.type?404:200,e.type)}),o.head.appendChild(t[0])},abort:function(){n&&n()}}}});var hn=[],dn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=hn.pop()||x.expando+"_"+Yt++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,s,a=t.jsonp!==!1&&(dn.test(t.url)?"url":"string"==typeof t.data&&!(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&dn.test(t.data)&&"data");return a||"jsonp"===t.dataTypes[0]?(i=t.jsonpCallback=x.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,a?t[a]=t[a].replace(dn,"$1"+i):t.jsonp!==!1&&(t.url+=(Vt.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return s||x.error(i+" was not called"),s[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){s=arguments},r.always(function(){e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,hn.push(i)),s&&x.isFunction(o)&&o(s[0]),s=o=undefined}),"script"):undefined}),x.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(e){}};var gn=x.ajaxSettings.xhr(),mn={0:200,1223:204},yn=0,vn={};e.ActiveXObject&&x(e).on("unload",function(){for(var e in vn)vn[e]();vn=undefined}),x.support.cors=!!gn&&"withCredentials"in gn,x.support.ajax=gn=!!gn,x.ajaxTransport(function(e){var t;return x.support.cors||gn&&!e.crossDomain?{send:function(n,r){var i,o,s=e.xhr();if(s.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(i in e.xhrFields)s[i]=e.xhrFields[i];e.mimeType&&s.overrideMimeType&&s.overrideMimeType(e.mimeType),e.crossDomain||n["X-Requested-With"]||(n["X-Requested-With"]="XMLHttpRequest");for(i in n)s.setRequestHeader(i,n[i]);t=function(e){return function(){t&&(delete vn[o],t=s.onload=s.onerror=null,"abort"===e?s.abort():"error"===e?r(s.status||404,s.statusText):r(mn[s.status]||s.status,s.statusText,"string"==typeof s.responseText?{text:s.responseText}:undefined,s.getAllResponseHeaders()))}},s.onload=t(),s.onerror=t("error"),t=vn[o=yn++]=t("abort"),s.send(e.hasContent&&e.data||null)},abort:function(){t&&t()}}:undefined});var xn,bn,wn=/^(?:toggle|show|hide)$/,Tn=RegExp("^(?:([+-])=|)("+b+")([a-z%]*)$","i"),Cn=/queueHooks$/,kn=[An],Nn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Tn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),s=(x.cssNumber[e]||"px"!==o&&+r)&&Tn.exec(x.css(n.elem,e)),a=1,u=20;if(s&&s[3]!==o){o=o||s[3],i=i||[],s=+r||1;do a=a||".5",s/=a,x.style(n.elem,e,s+o);while(a!==(a=n.cur()/r)&&1!==a&&--u)}return i&&(s=n.start=+s||+r||0,n.unit=o,n.end=i[1]?s+(i[1]+1)*i[2]:+i[2]),n}]};function En(){return setTimeout(function(){xn=undefined}),xn=x.now()}function Sn(e,t,n){var r,i=(Nn[t]||[]).concat(Nn["*"]),o=0,s=i.length;for(;s>o;o++)if(r=i[o].call(n,t,e))return r}function jn(e,t,n){var r,i,o=0,s=kn.length,a=x.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=xn||En(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,s=0,u=l.tweens.length;for(;u>s;s++)l.tweens[s].run(o);return a.notifyWith(e,[l,o,n]),1>o&&u?n:(a.resolveWith(e,[l]),!1)},l=a.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:xn||En(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?a.resolveWith(e,[l,t]):a.rejectWith(e,[l,t]),this}}),c=l.props;for(Dn(c,l.opts.specialEasing);s>o;o++)if(r=kn[o].call(l,e,c,l.opts))return r;return x.map(c,Sn,l),x.isFunction(l.opts.start)&&l.opts.start.call(e,l),x.fx.timer(x.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function Dn(e,t){var n,r,i,o,s;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),s=x.cssHooks[r],s&&"expand"in s){o=s.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(jn,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Nn[n]=Nn[n]||[],Nn[n].unshift(t)},prefilter:function(e,t){t?kn.unshift(e):kn.push(e)}});function An(e,t,n){var r,i,o,s,a,u,l=this,c={},p=e.style,f=e.nodeType&&Lt(e),h=q.get(e,"fxshow");n.queue||(a=x._queueHooks(e,"fx"),null==a.unqueued&&(a.unqueued=0,u=a.empty.fire,a.empty.fire=function(){a.unqueued||u()}),a.unqueued++,l.always(function(){l.always(function(){a.unqueued--,x.queue(e,"fx").length||a.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(p.display="inline-block")),n.overflow&&(p.overflow="hidden",l.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],wn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show")){if("show"!==i||!h||h[r]===undefined)continue;f=!0}c[r]=h&&h[r]||x.style(e,r)}if(!x.isEmptyObject(c)){h?"hidden"in h&&(f=h.hidden):h=q.access(e,"fxshow",{}),o&&(h.hidden=!f),f?x(e).show():l.done(function(){x(e).hide()}),l.done(function(){var t;q.remove(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)s=Sn(f?h[r]:0,r,l),r in h||(h[r]=s.start,f&&(s.end=s.start,s.start="width"===r||"height"===r?1:0))}}function Ln(e,t,n,r,i){return new Ln.prototype.init(e,t,n,r,i)}x.Tween=Ln,Ln.prototype={constructor:Ln,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=Ln.propHooks[this.prop];return e&&e.get?e.get(this):Ln.propHooks._default.get(this)},run:function(e){var t,n=Ln.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ln.propHooks._default.set(this),this}},Ln.prototype.init.prototype=Ln.prototype,Ln.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Ln.propHooks.scrollTop=Ln.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(qn(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Lt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),s=function(){var t=jn(this,x.extend({},e),o);(i||q.get(this,"finish"))&&t.stop(!0)};return s.finish=s,i||o.queue===!1?this.each(s):this.queue(o.queue,s)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=undefined),t&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,i=null!=e&&e+"queueHooks",o=x.timers,s=q.get(this);if(i)s[i]&&s[i].stop&&r(s[i]);else for(i in s)s[i]&&s[i].stop&&Cn.test(i)&&r(s[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));(t||!n)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=q.get(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,s=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;s>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function qn(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=jt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:qn("show"),slideUp:qn("hide"),slideToggle:qn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=Ln.prototype.init,x.fx.tick=function(){var e,t=x.timers,n=0;for(xn=x.now();t.length>n;n++)e=t[n],e()||t[n]!==e||t.splice(n--,1);t.length||x.fx.stop(),xn=undefined},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){bn||(bn=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(bn),bn=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===undefined?this:this.each(function(t){x.offset.setOffset(this,e,t)});var t,n,i=this[0],o={top:0,left:0},s=i&&i.ownerDocument;if(s)return t=s.documentElement,x.contains(t,i)?(typeof i.getBoundingClientRect!==r&&(o=i.getBoundingClientRect()),n=Hn(s),{top:o.top+n.pageYOffset-t.clientTop,left:o.left+n.pageXOffset-t.clientLeft}):o},x.offset={setOffset:function(e,t,n){var r,i,o,s,a,u,l,c=x.css(e,"position"),p=x(e),f={};"static"===c&&(e.style.position="relative"),a=p.offset(),o=x.css(e,"top"),u=x.css(e,"left"),l=("absolute"===c||"fixed"===c)&&(o+u).indexOf("auto")>-1,l?(r=p.position(),s=r.top,i=r.left):(s=parseFloat(o)||0,i=parseFloat(u)||0),x.isFunction(t)&&(t=t.call(e,n,a)),null!=t.top&&(f.top=t.top-a.top+s),null!=t.left&&(f.left=t.left-a.left+i),"using"in t?t.using.call(e,f):p.css(f)}},x.fn.extend({position:function(){if(this[0]){var e,t,n=this[0],r={top:0,left:0};return"fixed"===x.css(n,"position")?t=n.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(r=e.offset()),r.top+=x.css(e[0],"borderTopWidth",!0),r.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-r.top-x.css(n,"marginTop",!0),left:t.left-r.left-x.css(n,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,n){var r="pageYOffset"===n;x.fn[t]=function(i){return x.access(this,function(t,i,o){var s=Hn(t);return o===undefined?s?s[n]:t[i]:(s?s.scrollTo(r?e.pageXOffset:o,r?o:e.pageYOffset):t[i]=o,undefined)},t,i,arguments.length,null)}});function Hn(e){return x.isWindow(e)?e:9===e.nodeType&&e.defaultView}x.each({Height:"height",Width:"width"},function(e,t){x.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){x.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),s=n||(r===!0||i===!0?"margin":"border");return x.access(this,function(t,n,r){var i;return x.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):r===undefined?x.css(t,n,s):x.style(t,n,r,s)},t,o?r:undefined,o,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}),"object"==typeof e&&"object"==typeof e.document&&(e.jQuery=e.$=x)})(window);
--- /dev/null
+/**
+ * Copyright 2013 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.
+ */
+
+@import "normalize.css";
+
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+/* Fonts */
+
+body {
+ font: 13px Arial, sans-serif;
+ line-height: 165%;
+}
+
+h1, .sidebar .location {
+ font: 700 22px "Oswald", Arial, sans-serif;
+}
+
+h2, h3, h4 {
+ font: 700 16px "Oswald", Arial, sans-serif;
+ text-transform: uppercase;
+}
+
+h2 code, h3 code, h4 code {
+ text-transform: none;
+ font-size: 1.2em;
+}
+
+code, pre, h1.fqn {
+ font: 15px "Inconsolata", "Consolas", "Courier New", monospace;
+}
+h1.fqn {
+ font-size: 26px;
+ font-weight: normal;
+}
+
+nav {
+ font: 700 26px "Oswald", Arial, sans-serif;
+ text-transform: uppercase;
+}
+
+nav.sub {
+ padding-top: 20px;
+ font: 700 16px "Oswald", Arial, sans-serif;
+ text-transform: uppercase;
+ text-align: right;
+}
+
+/* General structure */
+
+html, body {
+ min-height: 100%;
+ height: 100%;
+}
+
+body {
+ position: relative;
+ height: auto;
+ padding-bottom: 20px;
+}
+
+.sidebar {
+ width: 200px;
+ position: absolute;
+ left: 0;
+ top: 0;
+ min-height: 100%;
+}
+
+.content, nav { max-width: 960px; }
+
+/* Everything else */
+
+.js-only, .hidden { display: none; }
+
+.sidebar {
+ background: #e9e9e9;
+ padding: 10px;
+}
+
+.sidebar img {
+ margin: 20px auto;
+ display: block;
+}
+
+.sidebar .location { margin-bottom: 10px; }
+.sidebar .block, pre { background: #fff; }
+.sidebar .block, pre, .content { border-bottom: 2px solid black; }
+.trait { border-color: #fcae2b !important; }
+.mod { border-color: #809fc7 !important; }
+.enum { border-color: #93bc99 !important; }
+.struct { border-color: #e53700 !important; }
+.fn { border-color: #a2777f !important; }
+
+.block {
+ padding: 10px;
+ margin-bottom: 10px;
+}
+.block h2 { margin-top: 0; }
+
+.content {
+ background: #f3f3f3;
+ padding: 20px 20px 20px 40px;
+}
+.content h1 { margin-top: 0; }
+.content h1, .content h2 { margin-left: -20px; }
+.content pre { padding: 20px; }
+
+.content .highlighted {
+ cursor: pointer;
+ color: #000 !important;
+ background-color: #ccc;
+}
+.content .highlighted a { color: #000 !important; }
+.content .highlighted.trait { background-color: #fece7e; }
+.content .highlighted.mod { background-color: #afc6e4; }
+.content .highlighted.enum { background-color: #b4d1b9; }
+.content .highlighted.struct { background-color: #e7b1a0; }
+.content .highlighted.fn { background-color: #c6afb3; }
+
+.docblock.short.nowrap {
+ display: block;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+.docblock.short p {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ margin: 0;
+}
+
+.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
+ margin-left: 0;
+}
+
+.docblock h1 { font-size: 1.1em; }
+.docblock h2 { font-size: 1.05em; }
+.docblock h3, .docblock h4, .docblock h5 { font-size: 1em; }
+
+.content .source { float: right; }
+.content table {
+ border-spacing: 0 5px;
+ border-collapse: separate;
+}
+.content td { vertical-align: top; }
+.content td:first-child { padding-right: 20px; }
+.content td p:first-child { margin-top: 0; }
+.content td h1, .content td h2 { margin-left: 0; font-size: 1.1em; }
+
+.content .item-list {
+ list-style-type: none;
+ padding: 0;
+}
+
+.content .item-list li { margin-bottom: 3px; }
+
+.content .multi-column {
+ -moz-column-count: 5;
+ -moz-column-gap: 2.5em;
+ -webkit-column-count: 5;
+ -webkit-column-gap: 2.5em;
+ column-count: 5;
+ column-gap: 2.5em;
+}
+.content .multi-column li { width: 100%; display: inline-block; }
+
+.content .method { font-size: 1em; }
+.content .methods { margin-left: 20px; }
+.content .methods .docblock { margin-left: 20px; }
+
+nav {
+ border-bottom: 1px solid #e0e0e0;
+ padding-bottom: 10px;
+ margin-bottom: 10px;
+}
+nav.main {
+ padding: 20px 0;
+ text-align: center;
+}
+nav.main .current {
+ border-top: 1px solid #000;
+ border-bottom: 1px solid #000;
+}
+nav.main .separator {
+ border: 1px solid #000;
+ display: inline-block;
+ height: 23px;
+ margin: 0 20px;
+}
+nav.sum { text-align: right; }
+nav.sub form { display: inline; }
+
+nav, .content {
+ margin-left: 220px;
+ margin-right: 20px;
+}
+
+a {
+ text-decoration: none;
+ color: #000;
+}
+
+.content a, .block a.current { font-weight: bold; }
+
+.content a.trait, .block a.current.trait { color: #ed9603; }
+.content a.mod, .block a.current.mod { color: #4d76ae; }
+.content a.enum, .block a.current.enum { color: #5e9766; }
+.content a.struct, .block a.current.struct { color: #e53700; }
+.content a.fn, .block a.current.fn { color: #8c6067; }
+
+.search-input {
+ border: 2px solid #f2f2f2;
+ border-radius: 2px;
+ width: 350px;
+}
+.search-results .desc {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ display: block;
+}
+
+#help {
+ background: #e9e9e9;
+ border-radius: 4px;
+ box-shadow: 0 0 6px rgba(0,0,0,.2);
+
+ position: absolute;
+ top: 300px;
+ left: 50%;
+ margin-top: -125px;
+ margin-left: -275px;
+ width: 550px;
+ height: 250px;
+ border: 1px solid #bfbfbf;
+}
+
+#help dt {
+ float: left;
+ border-radius: 3px;
+ border: 1px solid #bfbfbf;
+ background: #fff;
+ width: 23px;
+ text-align: center;
+ clear: left;
+ display: block;
+ margin-top: -1px;
+}
+#help dd { margin: 5px 33px; }
+#help .infos { padding-left: 0; }
+#help h1 { margin-top: 0; }
+#help div {
+ width: 50%;
+ float: left;
+ padding: 20px;
+}
--- /dev/null
+// Copyright 2013 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.
+
+/*jslint browser: true, es5: true */
+/*globals $: true, searchIndex: true, rootPath: true, allPaths: true */
+
+(function () {
+ "use strict";
+ var resizeTimeout, interval;
+
+ $('.js-only').removeClass('js-only');
+
+ function resizeShortBlocks() {
+ if (resizeTimeout) {
+ clearTimeout(resizeTimeout);
+ }
+ resizeTimeout = setTimeout(function () {
+ var contentWidth = $('.content').width();
+ $('.docblock.short').width(function () {
+ return contentWidth - 40 - $(this).prev().width();
+ }).addClass('nowrap');
+ }, 150);
+ }
+ resizeShortBlocks();
+ $(window).on('resize', resizeShortBlocks);
+
+ $(document).on('keyup', function (e) {
+ if (document.activeElement.tagName === 'INPUT') {
+ return;
+ }
+
+ if (e.keyCode === 188 && $('#help').hasClass('hidden')) { // question mark
+ e.preventDefault();
+ $('#help').removeClass('hidden');
+ } else if (e.keyCode === 27 && !$('#help').hasClass('hidden')) { // esc
+ e.preventDefault();
+ $('#help').addClass('hidden');
+ } else if (e.keyCode === 83) { // S
+ e.preventDefault();
+ $('.search-input').focus();
+ }
+ }).on('click', function (e) {
+ if (!$(e.target).closest('#help').length) {
+ $('#help').addClass('hidden');
+ }
+ });
+
+ $('.version-selector').on('change', function () {
+ var i, match,
+ url = document.location.href,
+ stripped = '',
+ len = rootPath.match(/\.\.\//g).length + 1;
+
+ for (i = 0; i < len; i += 1) {
+ match = url.match(/\/[^\/]*$/);
+ if (i < len - 1) {
+ stripped = match[0] + stripped;
+ }
+ url = url.substring(0, url.length - match[0].length);
+ }
+
+ url += '/' + $('.version-selector').val() + stripped;
+
+ document.location.href = url;
+ });
+
+ function initSearch(searchIndex) {
+ var currentResults, index;
+
+ // clear cached values from the search bar
+ $(".search-input")[0].value = '';
+
+ function execQuery(query, max, searchWords) {
+ var valLower = query.query.toLowerCase(),
+ val = valLower,
+ typeFilter = query.type,
+ results = [],
+ aa = 0,
+ bb = 0;
+
+ // quoted values mean literal search
+ bb = searchWords.length;
+ if ((val.charAt(0) === "\"" || val.charAt(0) === "'") && val.charAt(val.length - 1) === val.charAt(0)) {
+ val = val.substr(1, val.length - 2);
+ for (aa = 0; aa < bb; aa += 1) {
+ if (searchWords[aa] === val) {
+ // filter type: ... queries
+ if (!typeFilter || typeFilter === searchIndex[aa].ty) {
+ results.push([aa, -1]);
+ }
+ }
+ if (results.length === max) {
+ break;
+ }
+ }
+ } else {
+ // gather matching search results up to a certain maximum
+ val = val.replace(/\_/g, "");
+ for (aa = 0; aa < bb; aa += 1) {
+ if (searchWords[aa].indexOf(val) > -1 || searchWords[aa].replace(/_/g, "").indexOf(val) > -1) {
+ // filter type: ... queries
+ if (!typeFilter || typeFilter === searchIndex[aa].ty) {
+ results.push([aa, searchWords[aa].replace(/_/g, "").indexOf(val)]);
+ }
+ }
+ if (results.length === max) {
+ break;
+ }
+ }
+ }
+ bb = results.length;
+ for (aa = 0; aa < bb; aa += 1) {
+ results[aa].push(searchIndex[results[aa][0]].ty);
+ }
+ for (aa = 0; aa < bb; aa += 1) {
+ results[aa].push(searchIndex[results[aa][0]].path);
+ }
+
+ // if there are no results then return to default and fail
+ if (results.length === 0) {
+ return [];
+ }
+
+ // sort by exact match
+ results.sort(function search_complete_sort0(aaa, bbb) {
+ if (searchWords[aaa[0]] === valLower && searchWords[bbb[0]] !== valLower) {
+ return 1;
+ }
+ });
+ // first sorting attempt
+ // sort by item name length
+ results.sort(function search_complete_sort1(aaa, bbb) {
+ if (searchWords[aaa[0]].length > searchWords[bbb[0]].length) {
+ return 1;
+ }
+ });
+ // second sorting attempt
+ // sort by item name
+ results.sort(function search_complete_sort1(aaa, bbb) {
+ if (searchWords[aaa[0]].length === searchWords[bbb[0]].length && searchWords[aaa[0]] > searchWords[bbb[0]]) {
+ return 1;
+ }
+ });
+ // third sorting attempt
+ // sort by index of keyword in item name
+ if (results[0][1] !== -1) {
+ results.sort(function search_complete_sort1(aaa, bbb) {
+ if (aaa[1] > bbb[1] && bbb[1] === 0) {
+ return 1;
+ }
+ });
+ }
+ // fourth sorting attempt
+ // sort by type
+ results.sort(function search_complete_sort3(aaa, bbb) {
+ if (searchWords[aaa[0]] === searchWords[bbb[0]] && aaa[2] > bbb[2]) {
+ return 1;
+ }
+ });
+ // fifth sorting attempt
+ // sort by path
+ results.sort(function search_complete_sort4(aaa, bbb) {
+ if (searchWords[aaa[0]] === searchWords[bbb[0]] && aaa[2] === bbb[2] && aaa[3] > bbb[3]) {
+ return 1;
+ }
+ });
+ // sixth sorting attempt
+ // remove duplicates, according to the data provided
+ for (aa = results.length - 1; aa > 0; aa -= 1) {
+ if (searchWords[results[aa][0]] === searchWords[results[aa - 1][0]] && results[aa][2] === results[aa - 1][2] && results[aa][3] === results[aa - 1][3]) {
+ results[aa][0] = -1;
+ }
+ }
+
+ return results;
+ }
+
+ function getQuery() {
+ var matches, type, query = $('.search-input').val();
+
+ matches = query.match(/^(fn|mod|str(uct)?|enum|trait|t(ype)?d(ef)?)\s*:\s*/i);
+ if (matches) {
+ type = matches[1].replace(/^td$/, 'typedef').replace(/^str$/, 'struct').replace(/^tdef$/, 'typedef').replace(/^typed$/, 'typedef');
+ query = query.substring(matches[0].length);
+ }
+
+ return {
+ query: query,
+ type: type,
+ id: query + type,
+ };
+ }
+
+ function initSearchNav() {
+ var hoverTimeout, $results = $('.search-results .result');
+
+ $results.on('click', function () {
+ document.location.href = $(this).find('a').prop('href');
+ }).on('mouseover', function () {
+ var $el = $(this);
+ clearTimeout(hoverTimeout);
+ hoverTimeout = setTimeout(function () {
+ $results.removeClass('highlighted');
+ $el.addClass('highlighted');
+ }, 20);
+ });
+
+ $(document).off('keyup.searchnav');
+ $(document).on('keyup.searchnav', function (e) {
+ var $active = $results.filter('.highlighted');
+
+ if (e.keyCode === 38) { // up
+ e.preventDefault();
+ if (!$active.length || !$active.prev()) {
+ return;
+ }
+
+ $active.prev().addClass('highlighted');
+ $active.removeClass('highlighted');
+ } else if (e.keyCode === 40) { // down
+ e.preventDefault();
+ if (!$active.length) {
+ $results.first().addClass('highlighted');
+ } else if ($active.next().length) {
+ $active.next().addClass('highlighted');
+ $active.removeClass('highlighted');
+ }
+ } else if (e.keyCode === 13) { // return
+ e.preventDefault();
+ if ($active.length) {
+ document.location.href = $active.find('a').prop('href');
+ }
+ }
+ });
+ }
+
+ function showResults(results) {
+ var output, shown, query = getQuery();
+
+ currentResults = query.id;
+ output = '<h1>Results for ' + query.query + (query.type ? ' (type: ' + query.type + ')' : '') + '</h1>';
+ output += '<table class="search-results">';
+
+ if (results.length > 0) {
+ shown = [];
+
+ results.forEach(function (item) {
+ var name, type;
+
+ if (shown.indexOf(item) !== -1) {
+ return;
+ }
+
+ shown.push(item);
+ name = item.name;
+ type = item.ty;
+
+ output += '<tr class="' + type + ' result"><td>';
+
+ if (type === 'mod') {
+ output += item.path + '::<a href="' + rootPath + item.path.replace(/::/g, '/') + '/' + name + '/index.html" class="' + type + '">' + name + '</a>';
+ } else if (type === 'static' || type === 'reexport') {
+ output += item.path + '::<a href="' + rootPath + item.path.replace(/::/g, '/') + '/index.html" class="' + type + '">' + name + '</a>';
+ } else if (item.parent !== undefined) {
+ var myparent = allPaths[item.parent];
+ output += item.path + '::' + myparent.name + '::<a href="' + rootPath + item.path.replace(/::/g, '/') + '/' + myparent.type + '.' + myparent.name + '.html" class="' + type + '">' + name + '</a>';
+ } else {
+ output += item.path + '::<a href="' + rootPath + item.path.replace(/::/g, '/') + '/' + type + '.' + name + '.html" class="' + type + '">' + name + '</a>';
+ }
+
+ output += '</td><td><span class="desc">' + item.desc + '</span></td></tr>';
+ });
+ } else {
+ output += 'No results :( <a href="https://duckduckgo.com/?q=' + encodeURIComponent('rust ' + query.query) + '">Try on DuckDuckGo?</a>';
+ }
+
+ output += "</p>";
+ $('.content').html(output);
+ $('.search-results .desc').width($('.content').width() - 40 - $('.content td:first-child').first().width());
+ initSearchNav();
+ }
+
+ function search(e) {
+ var query, filterdata = [], obj, i, len,
+ results = [],
+ maxResults = 200,
+ resultIndex;
+
+ query = getQuery();
+ if (e) {
+ e.preventDefault();
+ }
+
+ if (!query.query || query.id === currentResults) {
+ return;
+ }
+
+ resultIndex = execQuery(query, 20000, index);
+ len = resultIndex.length;
+ for (i = 0; i < len; i += 1) {
+ if (resultIndex[i][0] > -1) {
+ obj = searchIndex[resultIndex[i][0]];
+ filterdata.push([obj.name, obj.ty, obj.path, obj.desc]);
+ results.push(obj);
+ }
+ if (results.length >= maxResults) {
+ break;
+ }
+ }
+
+ // TODO add sorting capability through this function?
+ //
+ // // the handler for the table heading filtering
+ // filterdraw = function search_complete_filterdraw(node) {
+ // var name = "",
+ // arrow = "",
+ // op = 0,
+ // tbody = node.parentNode.parentNode.nextSibling,
+ // anchora = {},
+ // tra = {},
+ // tha = {},
+ // td1a = {},
+ // td2a = {},
+ // td3a = {},
+ // aaa = 0,
+ // bbb = 0;
+ //
+ // // the 4 following conditions set the rules for each
+ // // table heading
+ // if (node === ths[0]) {
+ // op = 0;
+ // name = "name";
+ // ths[1].innerHTML = ths[1].innerHTML.split(" ")[0];
+ // ths[2].innerHTML = ths[2].innerHTML.split(" ")[0];
+ // ths[3].innerHTML = ths[3].innerHTML.split(" ")[0];
+ // }
+ // if (node === ths[1]) {
+ // op = 1;
+ // name = "type";
+ // ths[0].innerHTML = ths[0].innerHTML.split(" ")[0];
+ // ths[2].innerHTML = ths[2].innerHTML.split(" ")[0];
+ // ths[3].innerHTML = ths[3].innerHTML.split(" ")[0];
+ // }
+ // if (node === ths[2]) {
+ // op = 2;
+ // name = "path";
+ // ths[0].innerHTML = ths[0].innerHTML.split(" ")[0];
+ // ths[1].innerHTML = ths[1].innerHTML.split(" ")[0];
+ // ths[3].innerHTML = ths[3].innerHTML.split(" ")[0];
+ // }
+ // if (node === ths[3]) {
+ // op = 3;
+ // name = "description";
+ // ths[0].innerHTML = ths[0].innerHTML.split(" ")[0];
+ // ths[1].innerHTML = ths[1].innerHTML.split(" ")[0];
+ // ths[2].innerHTML = ths[2].innerHTML.split(" ")[0];
+ // }
+ //
+ // // ascending or descending search
+ // arrow = node.innerHTML.split(" ")[1];
+ // if (arrow === undefined || arrow === "\u25b2") {
+ // arrow = "\u25bc";
+ // } else {
+ // arrow = "\u25b2";
+ // }
+ //
+ // // filter the data
+ // filterdata.sort(function search_complete_filterDraw_sort(xx, yy) {
+ // if ((arrow === "\u25b2" && xx[op].toLowerCase() < yy[op].toLowerCase()) || (arrow === "\u25bc" && xx[op].toLowerCase() > yy[op].toLowerCase())) {
+ // return 1;
+ // }
+ // });
+ // };
+
+ showResults(results);
+ }
+
+ function buildIndex(searchIndex) {
+ var len = searchIndex.length,
+ i = 0,
+ searchWords = [];
+
+ // before any analysis is performed lets gather the search terms to
+ // search against apart from the rest of the data. This is a quick
+ // operation that is cached for the life of the page state so that
+ // all other search operations have access to this cached data for
+ // faster analysis operations
+ for (i = 0; i < len; i += 1) {
+ if (typeof searchIndex[i].name === "string") {
+ searchWords.push(searchIndex[i].name.toLowerCase());
+ } else {
+ searchWords.push("");
+ }
+ }
+
+ return searchWords;
+ }
+
+ function startSearch() {
+ var keyUpTimeout;
+ $('.do-search').on('click', search);
+ $('.search-input').on('keyup', function () {
+ clearTimeout(keyUpTimeout);
+ keyUpTimeout = setTimeout(search, 100);
+ });
+ }
+
+ index = buildIndex(searchIndex);
+ startSearch();
+ }
+
+ initSearch(searchIndex);
+}());
--- /dev/null
+/*! normalize.css v2.1.2 | MIT License | git.io/normalize */
+
+/* ==========================================================================
+ HTML5 display definitions
+ ========================================================================== */
+
+/**
+ * Correct `block` display not defined in IE 8/9.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section,
+summary {
+ display: block;
+}
+
+/**
+ * Correct `inline-block` display not defined in IE 8/9.
+ */
+
+audio,
+canvas,
+video {
+ display: inline-block;
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+[hidden] {
+ display: none;
+}
+
+/* ==========================================================================
+ Base
+ ========================================================================== */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS text size adjust after orientation change, without disabling
+ * user zoom.
+ */
+
+html {
+ font-family: sans-serif; /* 1 */
+ -ms-text-size-adjust: 100%; /* 2 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Links
+ ========================================================================== */
+
+/**
+ * Address `outline` inconsistency between Chrome and other browsers.
+ */
+
+a:focus {
+ outline: thin dotted;
+}
+
+/**
+ * Improve readability when focused and also mouse hovered in all browsers.
+ */
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+/* ==========================================================================
+ Typography
+ ========================================================================== */
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari 5, and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/**
+ * Address styling not present in IE 8/9, Safari 5, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
+ */
+
+b,
+strong {
+ font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari 5 and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ height: 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+/**
+ * Correct font family set oddly in Safari 5 and Chrome.
+ */
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, serif;
+ font-size: 1em;
+}
+
+/**
+ * Improve readability of pre-formatted text in all browsers.
+ */
+
+pre {
+ white-space: pre-wrap;
+}
+
+/**
+ * Set consistent quote types.
+ */
+
+q {
+ quotes: "\201C" "\201D" "\2018" "\2019";
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+/* ==========================================================================
+ Embedded content
+ ========================================================================== */
+
+/**
+ * Remove border when inside `a` element in IE 8/9.
+ */
+
+img {
+ border: 0;
+}
+
+/**
+ * Correct overflow displayed oddly in IE 9.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* ==========================================================================
+ Figures
+ ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari 5.
+ */
+
+figure {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Forms
+ ========================================================================== */
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+ border: 0; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * 1. Correct font family not being inherited in all browsers.
+ * 2. Correct font size not being inherited in all browsers.
+ * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
+ */
+
+button,
+input,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 2 */
+ margin: 0; /* 3 */
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+button,
+input {
+ line-height: normal;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
+ * Correct `select` style inheritance in Firefox 4+ and Opera.
+ */
+
+button,
+select {
+ text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ * `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; /* 2 */
+ cursor: pointer; /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+/**
+ * 1. Address box sizing set to `content-box` in IE 8/9.
+ * 2. Remove excess padding in IE 8/9.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
+ * (include `-moz` to future-proof).
+ */
+
+input[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box; /* 2 */
+ box-sizing: content-box;
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari 5 and Chrome
+ * on OS X.
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/**
+ * 1. Remove default vertical scrollbar in IE 8/9.
+ * 2. Improve readability and alignment in all browsers.
+ */
+
+textarea {
+ overflow: auto; /* 1 */
+ vertical-align: top; /* 2 */
+}
+
+/* ==========================================================================
+ Tables
+ ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Build indexes as appropriate for the markdown pass
-
-
-use astsrv;
-use config;
-use doc::ItemUtils;
-use doc;
-use fold::Fold;
-use fold;
-use markdown_pass;
-use markdown_writer;
-use pass::Pass;
-
-pub fn mk_pass(config: config::Config) -> Pass {
- Pass {
- name: ~"markdown_index",
- f: |srv, doc| run(srv, doc, config.clone())
- }
-}
-
-pub fn run(
- _srv: astsrv::Srv,
- doc: doc::Doc,
- config: config::Config
-) -> doc::Doc {
- let fold = Fold {
- fold_mod: fold_mod,
- fold_nmod: fold_nmod,
- .. fold::default_any_fold(config)
- };
- (fold.fold_doc)(&fold, doc)
-}
-
-fn fold_mod(
- fold: &fold::Fold<config::Config>,
- doc: doc::ModDoc
-) -> doc::ModDoc {
-
- let doc = fold::default_any_fold_mod(fold, doc);
-
- doc::ModDoc {
- index: Some(build_mod_index(doc.clone(), fold.ctxt.clone())),
- .. doc
- }
-}
-
-fn fold_nmod(
- fold: &fold::Fold<config::Config>,
- doc: doc::NmodDoc
-) -> doc::NmodDoc {
-
- let doc = fold::default_any_fold_nmod(fold, doc);
-
- doc::NmodDoc {
- index: Some(build_nmod_index(doc.clone(), fold.ctxt.clone())),
- .. doc
- }
-}
-
-fn build_mod_index(
- doc: doc::ModDoc,
- config: config::Config
-) -> doc::Index {
- doc::Index {
- entries: doc.items.map(|doc| {
- item_to_entry((*doc).clone(), &config)
- })
- }
-}
-
-fn build_nmod_index(
- doc: doc::NmodDoc,
- config: config::Config
-) -> doc::Index {
- doc::Index {
- entries: doc.fns.map(|doc| {
- item_to_entry(doc::FnTag((*doc).clone()), &config)
- })
- }
-}
-
-fn item_to_entry(
- doc: doc::ItemTag,
- config: &config::Config
-) -> doc::IndexEntry {
- let link = match doc {
- doc::ModTag(_) | doc::NmodTag(_)
- if config.output_style == config::DocPerMod => {
- markdown_writer::make_filename(config,
- doc::ItemPage(doc.clone())).to_str()
- }
- _ => {
- ~"#" + pandoc_header_id(markdown_pass::header_text(doc.clone()))
- }
- };
-
- doc::IndexEntry {
- kind: markdown_pass::header_kind(doc.clone()),
- name: markdown_pass::header_name(doc.clone()),
- brief: doc.brief(),
- link: link
- }
-}
-
-pub fn pandoc_header_id(header: &str) -> ~str {
-
- // http://johnmacfarlane.net/pandoc/README.html#headers
-
- let header = remove_formatting(header);
- let header = remove_punctuation(header);
- let header = replace_with_hyphens(header);
- let header = convert_to_lowercase(header);
- let header = remove_up_to_first_letter(header);
- let header = maybe_use_section_id(header);
- return header;
-
- fn remove_formatting(s: &str) -> ~str {
- s.replace("`", "")
- }
- fn remove_punctuation(s: &str) -> ~str {
- let s = s.replace("<", "");
- let s = s.replace(">", "");
- let s = s.replace("[", "");
- let s = s.replace("]", "");
- let s = s.replace("(", "");
- let s = s.replace(")", "");
- let s = s.replace("@~", "");
- let s = s.replace("~", "");
- let s = s.replace("/", "");
- let s = s.replace(":", "");
- let s = s.replace("&", "");
- let s = s.replace("^", "");
- let s = s.replace(",", "");
- let s = s.replace("'", "");
- let s = s.replace("+", "");
- return s;
- }
- fn replace_with_hyphens(s: &str) -> ~str {
- // Collapse sequences of whitespace to a single dash
- // XXX: Hacky implementation here that only covers
- // one or two spaces.
- let s = s.trim();
- let s = s.replace(" ", "-");
- let s = s.replace(" ", "-");
- return s;
- }
- // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
- // to_ascii_consume and to_str_consume to not do a unnecessary copy.
- fn convert_to_lowercase(s: &str) -> ~str { s.to_ascii().to_lower().to_str_ascii() }
- fn remove_up_to_first_letter(s: &str) -> ~str { s.to_str() }
- fn maybe_use_section_id(s: &str) -> ~str { s.to_str() }
-}
-
-#[cfg(test)]
-mod test {
-
- use astsrv;
- use attr_pass;
- use config;
- use desc_to_brief_pass;
- use doc;
- use extract;
- use markdown_index_pass::run;
- use path_pass;
- use prune_hidden_pass;
- use super::pandoc_header_id;
-
- fn mk_doc(output_style: config::OutputStyle, source: ~str)
- -> doc::Doc {
- do astsrv::from_str(source) |srv| {
- let config = config::Config {
- output_style: output_style,
- .. config::default_config(&Path("whatever"))
- };
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
- let doc = (prune_hidden_pass::mk_pass().f)(srv.clone(), doc);
- let doc = (desc_to_brief_pass::mk_pass().f)(srv.clone(), doc);
- let doc = (path_pass::mk_pass().f)(srv.clone(), doc);
-
- run(srv.clone(), doc, config)
- }
- }
-
- #[test]
- fn should_remove_punctuation_from_headers() {
- assert!(pandoc_header_id("impl foo of bar<A>") ==
- ~"impl-foo-of-bara");
- assert!(pandoc_header_id("impl of num::num for int")
- == ~"impl-of-numnum-for-int");
- assert!(pandoc_header_id("impl of num::num for int/&")
- == ~"impl-of-numnum-for-int");
- assert!(pandoc_header_id("impl of num::num for ^int")
- == ~"impl-of-numnum-for-int");
- assert!(pandoc_header_id("impl for & condvar")
- == ~"impl-for-condvar");
- assert!(pandoc_header_id("impl of Select<T, U> for (Left, Right)")
- == ~"impl-of-selectt-u-for-left-right");
- assert!(pandoc_header_id("impl of Condition<'self, T, U>")
- == ~"impl-of-conditionself-t-u");
- assert!(pandoc_header_id("impl of Condition<T: Clone>")
- == ~"impl-of-conditiont-clone");
- }
-
- #[test]
- fn should_trim_whitespace_after_removing_punctuation() {
- assert_eq!(pandoc_header_id("impl foo for ()"), ~"impl-foo-for");
- }
-
- #[test]
- fn should_index_mod_contents() {
- let doc = mk_doc(
- config::DocPerCrate,
- ~"mod a { } fn b() { }"
- );
- assert!(doc.cratemod().index.unwrap().entries[0] == doc::IndexEntry {
- kind: ~"Module",
- name: ~"a",
- brief: None,
- link: ~"#module-a"
- });
- assert!(doc.cratemod().index.unwrap().entries[1] == doc::IndexEntry {
- kind: ~"Function",
- name: ~"b",
- brief: None,
- link: ~"#function-b"
- });
- }
-
- #[test]
- fn should_index_mod_contents_multi_page() {
- let doc = mk_doc(
- config::DocPerMod,
- ~"mod a { } fn b() { }"
- );
- assert_eq!(doc.cratemod().index.unwrap().entries[0], doc::IndexEntry {
- kind: ~"Module",
- name: ~"a",
- brief: None,
- link: ~"a.html"
- });
- assert_eq!(doc.cratemod().index.unwrap().entries[1], doc::IndexEntry {
- kind: ~"Function",
- name: ~"b",
- brief: None,
- link: ~"#function-b"
- });
- }
-
- #[test]
- fn should_add_brief_desc_to_index() {
- let doc = mk_doc(
- config::DocPerMod,
- ~"#[doc = \"test\"] mod a { }"
- );
- assert_eq!(doc.cratemod().index.unwrap().entries[0].brief, Some(~"test"));
- }
-
- #[test]
- fn should_index_foreign_mod_contents() {
- let doc = mk_doc(
- config::DocPerCrate,
- ~"extern { fn b(); }"
- );
- // hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().nmods()[0].index.unwrap().entries[0],
- doc::IndexEntry {
- kind: ~"Function",
- name: ~"b",
- brief: None,
- link: ~"#function-b"
- });
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Generate markdown from a document tree
-
-
-use astsrv;
-use doc::ItemUtils;
-use doc;
-use markdown_pass;
-use markdown_writer::Writer;
-use markdown_writer::WriterUtils;
-use markdown_writer::WriterFactory;
-use pass::Pass;
-use sort_pass;
-
-use std::cell::Cell;
-use std::str;
-use std::vec;
-use syntax;
-
-pub fn mk_pass(writer_factory: WriterFactory) -> Pass {
- let writer_factory = Cell::new(writer_factory);
- Pass {
- name: ~"markdown",
- f: |srv, doc| run(srv, doc, writer_factory.take())
- }
-}
-
-fn run(
- srv: astsrv::Srv,
- doc: doc::Doc,
- writer_factory: WriterFactory
-) -> doc::Doc {
-
- fn mods_last(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool {
- fn is_mod(item: &doc::ItemTag) -> bool {
- match *item {
- doc::ModTag(_) => true,
- _ => false
- }
- }
-
- let lteq = !is_mod(item1) || is_mod(item2);
- lteq
- }
-
- // Sort the items so mods come last. All mods will be
- // output at the same header level so sorting mods last
- // makes the headers come out nested correctly.
- let sorted_doc = (sort_pass::mk_pass(
- ~"mods last", mods_last
- ).f)(srv, doc.clone());
-
- write_markdown(sorted_doc, writer_factory);
-
- return doc;
-}
-
-struct Ctxt {
- w: Writer
-}
-
-pub fn write_markdown(
- doc: doc::Doc,
- writer_factory: WriterFactory
-) {
- // There is easy parallelism to be had here, but
- // we don't want to spawn too many pandoc processes.
- // (See #2484, which is closed.)
- do doc.pages.map |page| {
- let ctxt = Ctxt {
- w: writer_factory((*page).clone())
- };
- write_page(&ctxt, page)
- };
-}
-
-fn write_page(ctxt: &Ctxt, page: &doc::Page) {
- write_title(ctxt, (*page).clone());
- match (*page).clone() {
- doc::CratePage(doc) => {
- write_crate(ctxt, doc);
- }
- doc::ItemPage(doc) => {
- // We don't write a header for item's pages because their
- // header in the html output is created by the page title
- write_item_no_header(ctxt, doc);
- }
- }
- ctxt.w.put_done();
-}
-
-fn write_title(ctxt: &Ctxt, page: doc::Page) {
- ctxt.w.put_line(fmt!("%% %s", make_title(page)));
- ctxt.w.put_line(~"");
-}
-
-fn make_title(page: doc::Page) -> ~str {
- let item = match page {
- doc::CratePage(CrateDoc) => {
- doc::ModTag(CrateDoc.topmod.clone())
- }
- doc::ItemPage(ItemTag) => {
- ItemTag
- }
- };
- let title = markdown_pass::header_text(item);
- let title = title.replace("`", "");
- return title;
-}
-
-enum Hlvl {
- H1 = 1,
- H2 = 2,
- H3 = 3,
- H4 = 4
-}
-
-fn write_header(ctxt: &Ctxt, lvl: Hlvl, doc: doc::ItemTag) {
- let text = header_text(doc);
- write_header_(ctxt, lvl, text);
-}
-
-fn write_header_(ctxt: &Ctxt, lvl: Hlvl, title: ~str) {
- let hashes = str::from_chars(vec::from_elem(lvl as uint, '#'));
- ctxt.w.put_line(fmt!("%s %s", hashes, title));
- ctxt.w.put_line(~"");
-}
-
-pub fn header_kind(doc: doc::ItemTag) -> ~str {
- match doc {
- doc::ModTag(_) => {
- if doc.id() == syntax::ast::CRATE_NODE_ID {
- ~"Crate"
- } else {
- ~"Module"
- }
- }
- doc::NmodTag(_) => {
- ~"Foreign module"
- }
- doc::FnTag(_) => {
- ~"Function"
- }
- doc::StaticTag(_) => {
- ~"Static"
- }
- doc::EnumTag(_) => {
- ~"Enum"
- }
- doc::TraitTag(_) => {
- ~"Trait"
- }
- doc::ImplTag(_) => {
- ~"Implementation"
- }
- doc::TyTag(_) => {
- ~"Type"
- }
- doc::StructTag(_) => {
- ~"Struct"
- }
- }
-}
-
-pub fn header_name(doc: doc::ItemTag) -> ~str {
- let fullpath = (doc.path() + &[doc.name_()]).connect("::");
- match &doc {
- &doc::ModTag(_) if doc.id() != syntax::ast::CRATE_NODE_ID => {
- fullpath
- }
- &doc::NmodTag(_) => {
- fullpath
- }
- &doc::ImplTag(ref doc) => {
- assert!(doc.self_ty.is_some());
- let bounds = if doc.bounds_str.is_some() {
- fmt!(" where %s", *doc.bounds_str.get_ref())
- } else {
- ~""
- };
- let self_ty = doc.self_ty.get_ref();
- let mut trait_part = ~"";
- for (i, trait_type) in doc.trait_types.iter().enumerate() {
- if i == 0 {
- trait_part.push_str(" of ");
- } else {
- trait_part.push_str(", ");
- }
- trait_part.push_str(*trait_type);
- }
- fmt!("%s for %s%s", trait_part, *self_ty, bounds)
- }
- _ => {
- doc.name_()
- }
- }
-}
-
-pub fn header_text(doc: doc::ItemTag) -> ~str {
- match &doc {
- &doc::ImplTag(ref ImplDoc) => {
- let header_kind = header_kind(doc.clone());
- let bounds = if ImplDoc.bounds_str.is_some() {
- fmt!(" where `%s`", *ImplDoc.bounds_str.get_ref())
- } else {
- ~""
- };
- let desc = if ImplDoc.trait_types.is_empty() {
- fmt!("for `%s`%s", *ImplDoc.self_ty.get_ref(), bounds)
- } else {
- fmt!("of `%s` for `%s`%s",
- ImplDoc.trait_types[0],
- *ImplDoc.self_ty.get_ref(),
- bounds)
- };
- return fmt!("%s %s", header_kind, desc);
- }
- _ => {}
- }
-
- header_text_(header_kind(doc.clone()),
- header_name(doc))
-}
-
-fn header_text_(kind: &str, name: &str) -> ~str {
- fmt!("%s `%s`", kind, name)
-}
-
-fn write_crate(
- ctxt: &Ctxt,
- doc: doc::CrateDoc
-) {
- write_top_module(ctxt, doc.topmod.clone());
-}
-
-fn write_top_module(
- ctxt: &Ctxt,
- ModDoc: doc::ModDoc
-) {
- write_mod_contents(ctxt, ModDoc);
-}
-
-fn write_mod(
- ctxt: &Ctxt,
- ModDoc: doc::ModDoc
-) {
- write_mod_contents(ctxt, ModDoc);
-}
-
-fn write_common(
- ctxt: &Ctxt,
- desc: Option<~str>,
- sections: &[doc::Section]
-) {
- write_desc(ctxt, desc);
- write_sections(ctxt, sections);
-}
-
-fn write_desc(
- ctxt: &Ctxt,
- desc: Option<~str>
-) {
- match desc {
- Some(desc) => {
- ctxt.w.put_line(desc);
- ctxt.w.put_line(~"");
- }
- None => ()
- }
-}
-
-fn write_sections(ctxt: &Ctxt, sections: &[doc::Section]) {
- for section in sections.iter() {
- write_section(ctxt, (*section).clone());
- }
-}
-
-fn write_section(ctxt: &Ctxt, section: doc::Section) {
- write_header_(ctxt, H4, section.header.clone());
- ctxt.w.put_line(section.body.clone());
- ctxt.w.put_line(~"");
-}
-
-fn write_mod_contents(
- ctxt: &Ctxt,
- doc: doc::ModDoc
-) {
- write_common(ctxt, doc.desc(), doc.sections());
- if doc.index.is_some() {
- write_index(ctxt, doc.index.get_ref());
- }
-
- for itemTag in doc.items.iter() {
- write_item(ctxt, (*itemTag).clone());
- }
-}
-
-fn write_item(ctxt: &Ctxt, doc: doc::ItemTag) {
- write_item_(ctxt, doc, true);
-}
-
-fn write_item_no_header(ctxt: &Ctxt, doc: doc::ItemTag) {
- write_item_(ctxt, doc, false);
-}
-
-fn write_item_(ctxt: &Ctxt, doc: doc::ItemTag, write_header: bool) {
- if write_header {
- write_item_header(ctxt, doc.clone());
- }
-
- match doc {
- doc::ModTag(ModDoc) => write_mod(ctxt, ModDoc),
- doc::NmodTag(nModDoc) => write_nmod(ctxt, nModDoc),
- doc::FnTag(FnDoc) => write_fn(ctxt, FnDoc),
- doc::StaticTag(StaticDoc) => write_static(ctxt, StaticDoc),
- doc::EnumTag(EnumDoc) => write_enum(ctxt, EnumDoc),
- doc::TraitTag(TraitDoc) => write_trait(ctxt, TraitDoc),
- doc::ImplTag(ImplDoc) => write_impl(ctxt, ImplDoc),
- doc::TyTag(TyDoc) => write_type(ctxt, TyDoc),
- doc::StructTag(StructDoc) => put_struct(ctxt, StructDoc),
- }
-}
-
-fn write_item_header(ctxt: &Ctxt, doc: doc::ItemTag) {
- write_header(ctxt, item_header_lvl(&doc), doc);
-}
-
-fn item_header_lvl(doc: &doc::ItemTag) -> Hlvl {
- match doc {
- &doc::ModTag(_) | &doc::NmodTag(_) => H1,
- _ => H2
- }
-}
-
-fn write_index(ctxt: &Ctxt, index: &doc::Index) {
- if index.entries.is_empty() {
- return;
- }
-
- ctxt.w.put_line(~"<div class='index'>");
- ctxt.w.put_line(~"");
-
- for entry in index.entries.iter() {
- let header = header_text_(entry.kind, entry.name);
- let id = entry.link.clone();
- if entry.brief.is_some() {
- ctxt.w.put_line(fmt!("* [%s](%s) - %s",
- header, id, *entry.brief.get_ref()));
- } else {
- ctxt.w.put_line(fmt!("* [%s](%s)", header, id));
- }
- }
- ctxt.w.put_line(~"");
- ctxt.w.put_line(~"</div>");
- ctxt.w.put_line(~"");
-}
-
-fn write_nmod(ctxt: &Ctxt, doc: doc::NmodDoc) {
- write_common(ctxt, doc.desc(), doc.sections());
- if doc.index.is_some() {
- write_index(ctxt, doc.index.get_ref());
- }
-
- for FnDoc in doc.fns.iter() {
- write_item_header(ctxt, doc::FnTag((*FnDoc).clone()));
- write_fn(ctxt, (*FnDoc).clone());
- }
-}
-
-fn write_fn(
- ctxt: &Ctxt,
- doc: doc::FnDoc
-) {
- write_fnlike(ctxt, doc.sig.clone(), doc.desc(), doc.sections());
-}
-
-fn write_fnlike(
- ctxt: &Ctxt,
- sig: Option<~str>,
- desc: Option<~str>,
- sections: &[doc::Section]
-) {
- write_sig(ctxt, sig);
- write_common(ctxt, desc, sections);
-}
-
-fn write_sig(ctxt: &Ctxt, sig: Option<~str>) {
- match sig {
- Some(sig) => {
- ctxt.w.put_line(code_block(sig));
- ctxt.w.put_line(~"");
- }
- None => fail!("unimplemented")
- }
-}
-
-fn code_block(s: ~str) -> ~str {
- fmt!("~~~ {.rust}
-%s
-~~~", s)
-}
-
-fn write_static(
- ctxt: &Ctxt,
- doc: doc::StaticDoc
-) {
- write_sig(ctxt, doc.sig.clone());
- write_common(ctxt, doc.desc(), doc.sections());
-}
-
-fn write_enum(
- ctxt: &Ctxt,
- doc: doc::EnumDoc
-) {
- write_common(ctxt, doc.desc(), doc.sections());
- write_variants(ctxt, doc.variants);
-}
-
-fn write_variants(
- ctxt: &Ctxt,
- docs: &[doc::VariantDoc]
-) {
- if docs.is_empty() {
- return;
- }
-
- write_header_(ctxt, H4, ~"Variants");
-
- for variant in docs.iter() {
- write_variant(ctxt, (*variant).clone());
- }
-
- ctxt.w.put_line(~"");
-}
-
-fn write_variant(ctxt: &Ctxt, doc: doc::VariantDoc) {
- assert!(doc.sig.is_some());
- let sig = doc.sig.get_ref();
-
- // space out list items so they all end up within paragraph elements
- ctxt.w.put_line(~"");
-
- match doc.desc.clone() {
- Some(desc) => {
- ctxt.w.put_line(list_item_indent(fmt!("* `%s` - %s", *sig, desc)));
- }
- None => {
- ctxt.w.put_line(fmt!("* `%s`", *sig));
- }
- }
-}
-
-fn list_item_indent(item: &str) -> ~str {
- let indented = item.any_line_iter().collect::<~[&str]>();
-
- // separate markdown elements within `*` lists must be indented by four
- // spaces, or they will escape the list context. indenting everything
- // seems fine though.
- indented.connect("\n ")
-}
-
-fn write_trait(ctxt: &Ctxt, doc: doc::TraitDoc) {
- write_common(ctxt, doc.desc(), doc.sections());
- write_methods(ctxt, doc.methods);
-}
-
-fn write_methods(ctxt: &Ctxt, docs: &[doc::MethodDoc]) {
- for doc in docs.iter() {
- write_method(ctxt, (*doc).clone());
- }
-}
-
-fn write_method(ctxt: &Ctxt, doc: doc::MethodDoc) {
- write_header_(ctxt, H3, header_text_("Method", doc.name));
- write_fnlike(ctxt, doc.sig.clone(), doc.desc.clone(), doc.sections);
-}
-
-fn write_impl(ctxt: &Ctxt, doc: doc::ImplDoc) {
- write_common(ctxt, doc.desc(), doc.sections());
- write_methods(ctxt, doc.methods);
-}
-
-fn write_type(
- ctxt: &Ctxt,
- doc: doc::TyDoc
-) {
- write_sig(ctxt, doc.sig.clone());
- write_common(ctxt, doc.desc(), doc.sections());
-}
-
-fn put_struct(
- ctxt: &Ctxt,
- doc: doc::StructDoc
-) {
- write_sig(ctxt, doc.sig.clone());
- write_common(ctxt, doc.desc(), doc.sections());
-}
-
-#[cfg(test)]
-mod test {
-
- use astsrv;
- use attr_pass;
- use config;
- use desc_to_brief_pass;
- use doc;
- use extract;
- use markdown_index_pass;
- use markdown_pass::{mk_pass, write_markdown};
- use markdown_writer;
- use path_pass;
- use page_pass;
- use prune_hidden_pass;
- use sectionalize_pass;
- use trim_pass;
- use tystr_pass;
- use unindent_pass;
-
- fn render(source: ~str) -> ~str {
- let (srv, doc) = create_doc_srv(source);
- let markdown = write_markdown_str_srv(srv, doc);
- debug!("markdown: %s", markdown);
- markdown
- }
-
- fn create_doc_srv(source: ~str) -> (astsrv::Srv, doc::Doc) {
- do astsrv::from_str(source) |srv| {
-
- let config = config::Config {
- output_style: config::DocPerCrate,
- .. config::default_config(&Path("whatever"))
- };
-
- let doc = extract::from_srv(srv.clone(), ~"");
- debug!("doc (extract): %?", doc);
- let doc = (tystr_pass::mk_pass().f)(srv.clone(), doc);
- debug!("doc (tystr): %?", doc);
- let doc = (path_pass::mk_pass().f)(srv.clone(), doc);
- debug!("doc (path): %?", doc);
- let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
- debug!("doc (attr): %?", doc);
- let doc = (prune_hidden_pass::mk_pass().f)(srv.clone(), doc);
- debug!("doc (prune_hidden): %?", doc);
- let doc = (desc_to_brief_pass::mk_pass().f)(srv.clone(), doc);
- debug!("doc (desc_to_brief): %?", doc);
- let doc = (unindent_pass::mk_pass().f)(srv.clone(), doc);
- debug!("doc (unindent): %?", doc);
- let doc = (sectionalize_pass::mk_pass().f)(srv.clone(), doc);
- debug!("doc (trim): %?", doc);
- let doc = (trim_pass::mk_pass().f)(srv.clone(), doc);
- debug!("doc (sectionalize): %?", doc);
- let doc = (markdown_index_pass::mk_pass(config).f)(
- srv.clone(), doc);
- debug!("doc (index): %?", doc);
- (srv.clone(), doc)
- }
- }
-
- fn create_doc(source: ~str) -> doc::Doc {
- let (_, doc) = create_doc_srv(source);
- doc
- }
-
- fn write_markdown_str(
- doc: doc::Doc
- ) -> ~str {
- let (writer_factory, po) = markdown_writer::future_writer_factory();
- write_markdown(doc, writer_factory);
- return po.recv().second();
- }
-
- fn write_markdown_str_srv(
- srv: astsrv::Srv,
- doc: doc::Doc
- ) -> ~str {
- let (writer_factory, po) = markdown_writer::future_writer_factory();
- let pass = mk_pass(writer_factory);
- (pass.f)(srv, doc);
- return po.recv().second();
- }
-
- #[test]
- fn write_markdown_should_write_mod_headers() {
- let markdown = render(~"mod moo { }");
- assert!(markdown.contains("# Module `moo`"));
- }
-
- #[test]
- fn should_leave_blank_line_after_header() {
- let markdown = render(~"mod morp { }");
- assert!(markdown.contains("Module `morp`\n\n"));
- }
-
- #[test]
- fn should_write_modules_last() {
- /*
- Because the markdown pass writes all modules at the same level of
- indentation (it doesn't 'nest' them), we need to make sure that we
- write all of the modules contained in each module after all other
- types of items, or else the header nesting will end up wrong, with
- modules appearing to contain items that they do not.
- */
- let markdown = render(
- ~"mod a { }\
- fn b() { }\
- mod c {
-}\
- fn d() { }"
- );
-
- let idx_a = markdown.find_str("# Module `a`").unwrap();
- let idx_b = markdown.find_str("## Function `b`").unwrap();
- let idx_c = markdown.find_str("# Module `c`").unwrap();
- let idx_d = markdown.find_str("## Function `d`").unwrap();
-
- assert!(idx_b < idx_d);
- assert!(idx_d < idx_a);
- assert!(idx_a < idx_c);
- }
-
- #[test]
- fn should_request_new_writer_for_each_page() {
- // This port will send us a (page, str) pair for every writer
- // that was created
- let (writer_factory, po) = markdown_writer::future_writer_factory();
- let (srv, doc) = create_doc_srv(~"mod a { }");
- // Split the document up into pages
- let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc);
- write_markdown(doc, writer_factory);
- // We expect two pages to have been written
- for _ in range(0, 2u) {
- po.recv();
- }
- }
-
- #[test]
- fn should_write_title_for_each_page() {
- let (writer_factory, po) = markdown_writer::future_writer_factory();
- let (srv, doc) = create_doc_srv(
- ~"#[link(name = \"core\")]; mod a { }");
- let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc);
- write_markdown(doc, writer_factory);
- for _ in range(0, 2u) {
- let (page, markdown) = po.recv();
- match page {
- doc::CratePage(_) => {
- assert!(markdown.contains("% Crate core"));
- }
- doc::ItemPage(_) => {
- assert!(markdown.contains("% Module a"));
- }
- }
- }
- }
-
- #[test]
- fn should_write_full_path_to_mod() {
- let markdown = render(~"mod a { mod b { mod c { } } }");
- assert!(markdown.contains("# Module `a::b::c`"));
- }
-
- #[test]
- fn should_write_sections() {
- let markdown = render(
- ~"#[doc = \"\
- # Header\n\
- Body\"]\
- mod a {
-}");
- assert!(markdown.contains("#### Header\n\nBody\n\n"));
- }
-
- #[test]
- fn should_write_crate_description() {
- let markdown = render(~"#[doc = \"this is the crate\"];");
- assert!(markdown.contains("this is the crate"));
- }
-
-
- #[test]
- fn should_write_index() {
- let markdown = render(~"mod a { } mod b { }");
- assert!(markdown.contains(
- "\n\n* [Module `a`](#module-a)\n\
- * [Module `b`](#module-b)\n\n"
- ));
- }
-
- #[test]
- fn should_write_index_brief() {
- let markdown = render(~"#[doc = \"test\"] mod a { }");
- assert!(markdown.contains("(#module-a) - test\n"));
- }
-
- #[test]
- fn should_not_write_index_if_no_entries() {
- let markdown = render(~"");
- assert!(!markdown.contains("\n\n\n"));
- }
-
- #[test]
- fn should_write_index_for_foreign_mods() {
- let markdown = render(~"extern { fn a(); }");
- assert!(markdown.contains(
- "\n\n* [Function `a`](#function-a)\n\n"
- ));
- }
-
- #[test]
- fn should_write_foreign_fns() {
- let markdown = render(
- ~"extern { #[doc = \"test\"] fn a(); }");
- assert!(markdown.contains("test"));
- }
-
- #[test]
- fn should_write_foreign_fn_headers() {
- let markdown = render(
- ~"extern { #[doc = \"test\"] fn a(); }");
- assert!(markdown.contains("## Function `a`"));
- }
-
- #[test]
- fn write_markdown_should_write_function_header() {
- let markdown = render(~"fn func() { }");
- assert!(markdown.contains("## Function `func`"));
- }
-
- #[test]
- fn should_write_the_function_signature() {
- let markdown = render(~"#[doc = \"f\"] fn a() { }");
- assert!(markdown.contains("\n~~~ {.rust}\nfn a()\n"));
- }
-
- #[test]
- fn should_insert_blank_line_after_fn_signature() {
- let markdown = render(~"#[doc = \"f\"] fn a() { }");
- assert!(markdown.contains("fn a()\n~~~\n\n"));
- }
-
- #[test]
- fn should_correctly_bracket_fn_signature() {
- let doc = create_doc(~"fn a() { }");
- let doc = doc::Doc{
- pages: ~[
- doc::CratePage(doc::CrateDoc{
- topmod: doc::ModDoc{
- items: ~[doc::FnTag(doc::SimpleItemDoc{
- sig: Some(~"line 1\nline 2"),
- .. (doc.cratemod().fns()[0]).clone()
- })],
- .. doc.cratemod()
- },
- .. doc.CrateDoc()
- })
- ]
- };
- let markdown = write_markdown_str(doc);
- assert!(markdown.contains("~~~ {.rust}\nline 1\nline 2\n~~~"));
- }
-
- #[test]
- fn should_leave_blank_line_between_fn_header_and_sig() {
- let markdown = render(~"fn a() { }");
- assert!(markdown.contains("Function `a`\n\n~~~ {.rust}\nfn a()"));
- }
-
- #[test]
- fn should_write_static_header() {
- let markdown = render(~"static a: bool = true;");
- assert!(markdown.contains("## Static `a`\n\n"));
- }
-
- #[test]
- fn should_write_static_description() {
- let markdown = render(
- ~"#[doc = \"b\"]\
- static a: bool = true;");
- assert!(markdown.contains("\n\nb\n\n"));
- }
-
- #[test]
- fn should_write_enum_header() {
- let markdown = render(~"enum a { b }");
- assert!(markdown.contains("## Enum `a`\n\n"));
- }
-
- #[test]
- fn should_write_enum_description() {
- let markdown = render(~"#[doc = \"b\"] enum a { b }");
- assert!(markdown.contains("\n\nb\n\n"));
- }
-
- #[test]
- fn should_write_variant_list() {
- let markdown = render(
- ~"enum a { \
- #[doc = \"test\"] b, \
- #[doc = \"test\"] c }");
- assert!(markdown.contains(
- "\n\n#### Variants\n\
- \n\
- \n* `b` - test\
- \n\
- \n* `c` - test\n\n"));
- }
-
- #[test]
- fn should_write_variant_list_without_descs() {
- let markdown = render(~"enum a { b, c }");
- assert!(markdown.contains(
- "\n\n#### Variants\n\
- \n\
- \n* `b`\
- \n\
- \n* `c`\n\n"));
- }
-
- #[test]
- fn should_write_variant_list_with_indent() {
- let markdown = render(
- ~"enum a { #[doc = \"line 1\\n\\nline 2\"] b, c }");
- assert!(markdown.contains(
- "\n\n#### Variants\n\
- \n\
- \n* `b` - line 1\
- \n \
- \n line 2\
- \n\
- \n* `c`\n\n"));
- }
-
- #[test]
- fn should_write_variant_list_with_signatures() {
- let markdown = render(~"enum a { b(int), #[doc = \"a\"] c(int) }");
- assert!(markdown.contains(
- "\n\n#### Variants\n\
- \n\
- \n* `b(int)`\
- \n\
- \n* `c(int)` - a\n\n"));
- }
-
- #[test]
- fn should_write_trait_header() {
- let markdown = render(~"trait i { fn a(); }");
- assert!(markdown.contains("## Trait `i`"));
- }
-
- #[test]
- fn should_write_trait_desc() {
- let markdown = render(~"#[doc = \"desc\"] trait i { fn a(); }");
- assert!(markdown.contains("desc"));
- }
-
- #[test]
- fn should_write_trait_method_header() {
- let markdown = render(~"trait i { fn a(); }");
- assert!(markdown.contains("### Method `a`"));
- }
-
- #[test]
- fn should_write_trait_method_signature() {
- let markdown = render(~"trait i { fn a(&self); }");
- assert!(markdown.contains("\n~~~ {.rust}\nfn a(&self)"));
- }
-
- #[test]
- fn should_write_impl_header() {
- let markdown = render(~"impl int { fn a() { } }");
- assert!(markdown.contains("## Implementation for `int`"));
- }
-
- #[test]
- fn should_write_impl_header_with_bounds() {
- let markdown = render(~"impl <T> int<T> { }");
- assert!(markdown.contains("## Implementation for `int<T>` where `<T>`"));
- }
-
- #[test]
- fn should_write_impl_header_with_trait() {
- let markdown = render(~"impl j for int { fn a() { } }");
- assert!(markdown.contains(
- "## Implementation of `j` for `int`"));
- }
-
- #[test]
- fn should_write_impl_desc() {
- let markdown = render(
- ~"#[doc = \"desc\"] impl int { fn a() { } }");
- assert!(markdown.contains("desc"));
- }
-
- #[test]
- fn should_write_impl_method_header() {
- let markdown = render(
- ~"impl int { fn a() { } }");
- assert!(markdown.contains("### Method `a`"));
- }
-
- #[test]
- fn should_write_impl_method_signature() {
- let markdown = render(
- ~"impl int { fn a(&mut self) { } }");
- assert!(markdown.contains("~~~ {.rust}\nfn a(&mut self)"));
- }
-
- #[test]
- fn should_write_type_header() {
- let markdown = render(~"type t = int;");
- assert!(markdown.contains("## Type `t`"));
- }
-
- #[test]
- fn should_write_type_desc() {
- let markdown = render(
- ~"#[doc = \"desc\"] type t = int;");
- assert!(markdown.contains("\n\ndesc\n\n"));
- }
-
- #[test]
- fn should_write_type_signature() {
- let markdown = render(~"type t = int;");
- assert!(markdown.contains("\n\n~~~ {.rust}\ntype t = int\n~~~\n"));
- }
-
- #[test]
- fn should_put_struct_header() {
- let markdown = render(~"struct S { field: () }");
- assert!(markdown.contains("## Struct `S`\n\n"));
- }
-}
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-use config;
-use doc::ItemUtils;
-use doc;
-
-use std::comm::*;
-use std::comm;
-use std::io;
-use std::result;
-use std::run;
-use std::str;
-use std::task;
-use extra::future::Future;
-
-#[deriving(Clone)]
-pub enum WriteInstr {
- Write(~str),
- Done
-}
-
-pub type Writer = ~fn(v: WriteInstr);
-pub type WriterFactory = ~fn(page: doc::Page) -> Writer;
-
-pub trait WriterUtils {
- fn put_str(&self, str: ~str);
- fn put_line(&self, str: ~str);
- fn put_done(&self);
-}
-
-impl WriterUtils for Writer {
- fn put_str(&self, str: ~str) {
- (*self)(Write(str));
- }
-
- fn put_line(&self, str: ~str) {
- self.put_str(str + "\n");
- }
-
- fn put_done(&self) {
- (*self)(Done)
- }
-}
-
-pub fn make_writer_factory(config: config::Config) -> WriterFactory {
- match config.output_format {
- config::Markdown => {
- markdown_writer_factory(config)
- }
- config::PandocHtml => {
- pandoc_writer_factory(config)
- }
- }
-}
-
-fn markdown_writer_factory(config: config::Config) -> WriterFactory {
- let result: ~fn(page: doc::Page) -> Writer = |page| {
- markdown_writer(&config, page)
- };
- result
-}
-
-fn pandoc_writer_factory(config: config::Config) -> WriterFactory {
- let result: ~fn(doc::Page) -> Writer = |page| {
- pandoc_writer(&config, page)
- };
- result
-}
-
-fn markdown_writer(
- config: &config::Config,
- page: doc::Page
-) -> Writer {
- let filename = make_local_filename(config, page);
- do generic_writer |markdown| {
- write_file(&filename, markdown);
- }
-}
-
-fn pandoc_writer(
- config: &config::Config,
- page: doc::Page
-) -> Writer {
- assert!(config.pandoc_cmd.is_some());
- let pandoc_cmd = (*config.pandoc_cmd.get_ref()).clone();
- let filename = make_local_filename(config, page);
-
- let pandoc_args = ~[
- ~"--standalone",
- ~"--section-divs",
- ~"--from=markdown",
- ~"--to=html",
- ~"--css=rust.css",
- ~"--output=" + filename.to_str()
- ];
-
- do generic_writer |markdown| {
- use std::io::WriterUtil;
-
- debug!("pandoc cmd: %s", pandoc_cmd);
- debug!("pandoc args: %s", pandoc_args.connect(" "));
-
- let mut proc = run::Process::new(pandoc_cmd, pandoc_args, run::ProcessOptions::new());
-
- proc.input().write_str(markdown);
- let output = proc.finish_with_output();
-
- debug!("pandoc result: %i", output.status);
- if output.status != 0 {
- error!("pandoc-out: %s", str::from_utf8(output.output));
- error!("pandoc-err: %s", str::from_utf8(output.error));
- fail!("pandoc failed");
- }
- }
-}
-
-fn generic_writer(process: ~fn(markdown: ~str)) -> Writer {
- let (po, ch) = stream::<WriteInstr>();
- do task::spawn || {
- let mut markdown = ~"";
- let mut keep_going = true;
- while keep_going {
- match po.recv() {
- Write(s) => markdown.push_str(s),
- Done => keep_going = false
- }
- }
- process(markdown);
- };
- let result: ~fn(instr: WriteInstr) = |instr| ch.send(instr);
- result
-}
-
-pub fn make_local_filename(
- config: &config::Config,
- page: doc::Page
-) -> Path {
- let filename = make_filename(config, page);
- config.output_dir.push_rel(&filename)
-}
-
-pub fn make_filename(
- config: &config::Config,
- page: doc::Page
-) -> Path {
- let filename = {
- match page {
- doc::CratePage(doc) => {
- if config.output_format == config::PandocHtml &&
- config.output_style == config::DocPerMod {
- ~"index"
- } else {
- assert!(doc.topmod.name_() != ~"");
- doc.topmod.name_()
- }
- }
- doc::ItemPage(doc) => {
- (doc.path() + &[doc.name_()]).connect("_")
- }
- }
- };
- let ext = match config.output_format {
- config::Markdown => ~"md",
- config::PandocHtml => ~"html"
- };
-
- Path(filename).with_filetype(ext)
-}
-
-fn write_file(path: &Path, s: ~str) {
- use std::io::WriterUtil;
-
- match io::file_writer(path, [io::Create, io::Truncate]) {
- result::Ok(writer) => {
- writer.write_str(s);
- }
- result::Err(e) => fail!(e)
- }
-}
-
-pub fn future_writer_factory(
-) -> (WriterFactory, Port<(doc::Page, ~str)>) {
- let (markdown_po, markdown_ch) = stream();
- let markdown_ch = SharedChan::new(markdown_ch);
- let writer_factory: WriterFactory = |page| {
- let (writer_po, writer_ch) = comm::stream();
- let markdown_ch = markdown_ch.clone();
- do task::spawn || {
- let (writer, future) = future_writer();
- let mut future = future;
- writer_ch.send(writer);
- let s = future.get();
- markdown_ch.send((page.clone(), s));
- }
- writer_po.recv()
- };
-
- (writer_factory, markdown_po)
-}
-
-fn future_writer() -> (Writer, Future<~str>) {
- let (port, chan) = comm::stream();
- let writer: ~fn(instr: WriteInstr) = |instr| chan.send(instr.clone());
- let future = do Future::from_fn || {
- let mut res = ~"";
- loop {
- match port.recv() {
- Write(s) => res.push_str(s),
- Done => break
- }
- }
- res
- };
- (writer, future)
-}
-
-#[cfg(test)]
-mod test {
-
- use astsrv;
- use doc;
- use extract;
- use path_pass;
- use config;
- use super::make_local_filename;
-
- fn mk_doc(name: ~str, source: ~str) -> doc::Doc {
- do astsrv::from_str(source) |srv| {
- let doc = extract::from_srv(srv.clone(), name.clone());
- let doc = (path_pass::mk_pass().f)(srv.clone(), doc);
- doc
- }
- }
-
- #[test]
- fn should_use_markdown_file_name_based_off_crate() {
- let config = config::Config {
- output_dir: Path("output/dir"),
- output_format: config::Markdown,
- output_style: config::DocPerCrate,
- .. config::default_config(&Path("input/test.rc"))
- };
- let doc = mk_doc(~"test", ~"");
- let page = doc::CratePage(doc.CrateDoc());
- let filename = make_local_filename(&config, page);
- assert_eq!(filename.to_str(), ~"output/dir/test.md");
- }
-
- #[test]
- fn should_name_html_crate_file_name_index_html_when_doc_per_mod() {
- let config = config::Config {
- output_dir: Path("output/dir"),
- output_format: config::PandocHtml,
- output_style: config::DocPerMod,
- .. config::default_config(&Path("input/test.rc"))
- };
- let doc = mk_doc(~"", ~"");
- let page = doc::CratePage(doc.CrateDoc());
- let filename = make_local_filename(&config, page);
- assert_eq!(filename.to_str(), ~"output/dir/index.html");
- }
-
- #[test]
- fn should_name_mod_file_names_by_path() {
- let config = config::Config {
- output_dir: Path("output/dir"),
- output_format: config::PandocHtml,
- output_style: config::DocPerMod,
- .. config::default_config(&Path("input/test.rc"))
- };
- let doc = mk_doc(~"", ~"mod a { mod b { } }");
- // hidden __std_macros module at the start.
- let modb = doc.cratemod().mods()[1].mods()[0].clone();
- let page = doc::ItemPage(doc::ModTag(modb));
- let filename = make_local_filename(&config, page);
- assert_eq!(filename, Path("output/dir/a_b.html"));
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-Divides the document tree into pages.
-
-Each page corresponds is a logical section. There may be pages for
-individual modules, pages for the crate, indexes, etc.
-*/
-
-
-use astsrv;
-use config;
-use doc::ItemUtils;
-use doc;
-use fold::Fold;
-use fold;
-use pass::Pass;
-
-use std::comm::*;
-use std::task;
-use syntax::ast;
-
-#[cfg(test)] use doc::PageUtils;
-
-pub fn mk_pass(output_style: config::OutputStyle) -> Pass {
- Pass {
- name: ~"page",
- f: |srv, doc| run(srv, doc, output_style)
- }
-}
-
-pub fn run(
- _srv: astsrv::Srv,
- doc: doc::Doc,
- output_style: config::OutputStyle
-) -> doc::Doc {
-
- if output_style == config::DocPerCrate {
- return doc;
- }
-
- let (result_port, result_chan) = stream();
- let (page_port, page_chan) = stream();
- let page_chan = SharedChan::new(page_chan);
- do task::spawn {
- result_chan.send(make_doc_from_pages(&page_port));
- };
-
- find_pages(doc, page_chan);
- result_port.recv()
-}
-
-type PagePort = Port<Option<doc::Page>>;
-type PageChan = SharedChan<Option<doc::Page>>;
-
-fn make_doc_from_pages(page_port: &PagePort) -> doc::Doc {
- let mut pages = ~[];
- loop {
- let val = page_port.recv();
- if val.is_some() {
- pages.push(val.unwrap());
- } else {
- break;
- }
- }
- doc::Doc {
- pages: pages
- }
-}
-
-fn find_pages(doc: doc::Doc, page_chan: PageChan) {
- let fold = Fold {
- ctxt: page_chan.clone(),
- fold_crate: fold_crate,
- fold_mod: fold_mod,
- fold_nmod: fold_nmod,
- .. fold::default_any_fold(page_chan.clone())
- };
- (fold.fold_doc)(&fold, doc.clone());
-
- page_chan.send(None);
-}
-
-fn fold_crate(fold: &fold::Fold<PageChan>, doc: doc::CrateDoc)
- -> doc::CrateDoc {
- let doc = fold::default_seq_fold_crate(fold, doc);
-
- let page = doc::CratePage(doc::CrateDoc {
- topmod: strip_mod(doc.topmod.clone()),
- .. doc.clone()
- });
-
- fold.ctxt.send(Some(page));
-
- doc
-}
-
-fn fold_mod(fold: &fold::Fold<PageChan>, doc: doc::ModDoc) -> doc::ModDoc {
- let doc = fold::default_any_fold_mod(fold, doc);
-
- if doc.id() != ast::CRATE_NODE_ID {
-
- let doc = strip_mod(doc.clone());
- let page = doc::ItemPage(doc::ModTag(doc));
- fold.ctxt.send(Some(page));
- }
-
- doc
-}
-
-fn strip_mod(doc: doc::ModDoc) -> doc::ModDoc {
- doc::ModDoc {
- items: do doc.items.iter().filter |item| {
- match **item {
- doc::ModTag(_) | doc::NmodTag(_) => false,
- _ => true
- }
- }.map(|x| (*x).clone()).collect::<~[doc::ItemTag]>(),
- .. doc.clone()
- }
-}
-
-fn fold_nmod(fold: &fold::Fold<PageChan>, doc: doc::NmodDoc) -> doc::NmodDoc {
- let doc = fold::default_seq_fold_nmod(fold, doc);
- let page = doc::ItemPage(doc::NmodTag(doc.clone()));
- fold.ctxt.send(Some(page));
- return doc;
-}
-
-#[cfg(test)]
-mod test {
- use astsrv;
- use config;
- use attr_pass;
- use doc;
- use extract;
- use prune_hidden_pass;
- use page_pass::run;
-
- fn mk_doc_(
- output_style: config::OutputStyle,
- source: ~str
- ) -> doc::Doc {
- do astsrv::from_str(source.clone()) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
- let doc = (prune_hidden_pass::mk_pass().f)(srv.clone(), doc);
- run(srv.clone(), doc, output_style)
- }
- }
-
- fn mk_doc(source: ~str) -> doc::Doc {
- mk_doc_(config::DocPerMod, source.clone())
- }
-
- #[test]
- fn should_not_split_the_doc_into_pages_for_doc_per_crate() {
- let doc = mk_doc_(
- config::DocPerCrate,
- ~"mod a { } mod b { mod c { } }"
- );
- assert_eq!(doc.pages.len(), 1u);
- }
-
- #[test]
- fn should_make_a_page_for_every_mod() {
- let doc = mk_doc(~"mod a { }");
- // hidden __std_macros module at the start.
- assert_eq!(doc.pages.mods()[0].name_(), ~"a");
- }
-
- #[test]
- fn should_remove_mods_from_containing_mods() {
- let doc = mk_doc(~"mod a { }");
- assert!(doc.cratemod().mods().is_empty());
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! AST-parsing helpers
-
-use rustc::driver::driver;
-use rustc::driver::session;
-use syntax::ast;
-use syntax::parse;
-
-pub fn from_file(file: &Path) -> @ast::Crate {
- parse::parse_crate_from_file(
- file, ~[], parse::new_parse_sess(None))
-}
-
-pub fn from_str(source: @str) -> @ast::Crate {
- parse::parse_crate_from_source_str(
- @"-", source, ~[], parse::new_parse_sess(None))
-}
-
-pub fn from_file_sess(sess: session::Session, file: &Path) -> @ast::Crate {
- parse::parse_crate_from_file(
- file, cfg(sess), sess.parse_sess)
-}
-
-pub fn from_str_sess(sess: session::Session, source: @str) -> @ast::Crate {
- parse::parse_crate_from_source_str(
- @"-", source, cfg(sess), sess.parse_sess)
-}
-
-fn cfg(sess: session::Session) -> ast::CrateConfig {
- driver::build_configuration(sess)
-}
-
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-
-use astsrv;
-use doc;
-use time;
-
-#[cfg(test)] use extract;
-
-/// A single operation on the document model
-pub struct Pass {
- name: ~str,
- f: @fn(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc
-}
-
-pub fn run_passes(
- srv: astsrv::Srv,
- doc: doc::Doc,
- passes: ~[Pass]
-) -> doc::Doc {
- let mut passno = 0;
- do passes.iter().fold(doc) |doc, pass| {
- debug!("pass #%d", passno);
- passno += 1;
- do time(pass.name.clone()) {
- (pass.f)(srv.clone(), doc.clone())
- }
- }
-}
-
-#[test]
-fn test_run_passes() {
- fn pass1(
- _srv: astsrv::Srv,
- doc: doc::Doc
- ) -> doc::Doc {
- doc::Doc{
- pages: ~[
- doc::CratePage(doc::CrateDoc{
- topmod: doc::ModDoc{
- item: doc::ItemDoc {
- name: doc.cratemod().name_() + "two",
- .. doc.cratemod().item.clone()
- },
- items: ~[],
- index: None
- }
- })
- ]
- }
- }
- fn pass2(
- _srv: astsrv::Srv,
- doc: doc::Doc
- ) -> doc::Doc {
- doc::Doc{
- pages: ~[
- doc::CratePage(doc::CrateDoc{
- topmod: doc::ModDoc{
- item: doc::ItemDoc {
- name: doc.cratemod().name_() + "three",
- .. doc.cratemod().item.clone()
- },
- items: ~[],
- index: None
- }
- })
- ]
- }
- }
- let source = ~"";
- do astsrv::from_str(source) |srv| {
- let passes = ~[
- Pass {
- name: ~"",
- f: pass1
- },
- Pass {
- name: ~"",
- f: pass2
- }
- ];
- let doc = extract::from_srv(srv.clone(), ~"one");
- let doc = run_passes(srv, doc, passes);
- assert_eq!(doc.cratemod().name_(), ~"onetwothree");
- }
-}
--- /dev/null
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::num;
+use std::uint;
+
+use clean;
+use syntax::ast;
+use clean::Item;
+use plugins;
+use fold;
+use fold::DocFolder;
+
+/// Strip items marked `#[doc(hidden)]`
+pub fn strip_hidden(crate: clean::Crate) -> plugins::PluginResult {
+ struct Stripper;
+ impl fold::DocFolder for Stripper {
+ fn fold_item(&mut self, i: Item) -> Option<Item> {
+ for attr in i.attrs.iter() {
+ match attr {
+ &clean::List(~"doc", ref l) => {
+ for innerattr in l.iter() {
+ match innerattr {
+ &clean::Word(ref s) if "hidden" == *s => {
+ debug!("found one in strip_hidden; removing");
+ return None;
+ },
+ _ => (),
+ }
+ }
+ },
+ _ => ()
+ }
+ }
+ self.fold_item_recur(i)
+ }
+ }
+ let mut stripper = Stripper;
+ let crate = stripper.fold_crate(crate);
+ (crate, None)
+}
+
+pub fn unindent_comments(crate: clean::Crate) -> plugins::PluginResult {
+ struct CommentCleaner;
+ impl fold::DocFolder for CommentCleaner {
+ fn fold_item(&mut self, i: Item) -> Option<Item> {
+ let mut i = i;
+ let mut avec: ~[clean::Attribute] = ~[];
+ for attr in i.attrs.iter() {
+ match attr {
+ &clean::NameValue(~"doc", ref s) => avec.push(
+ clean::NameValue(~"doc", unindent(*s))),
+ x => avec.push(x.clone())
+ }
+ }
+ i.attrs = avec;
+ self.fold_item_recur(i)
+ }
+ }
+ let mut cleaner = CommentCleaner;
+ let crate = cleaner.fold_crate(crate);
+ (crate, None)
+}
+
+pub fn collapse_privacy(crate: clean::Crate) -> plugins::PluginResult {
+ struct PrivacyCollapser {
+ stack: ~[clean::Visibility]
+ }
+ impl fold::DocFolder for PrivacyCollapser {
+ fn fold_item(&mut self, mut i: Item) -> Option<Item> {
+ if i.visibility.is_some() {
+ if i.visibility == Some(ast::inherited) {
+ i.visibility = Some(self.stack.last().clone());
+ } else {
+ self.stack.push(i.visibility.clone().unwrap());
+ }
+ }
+ self.fold_item_recur(i)
+ }
+ }
+ let mut privacy = PrivacyCollapser { stack: ~[] };
+ let crate = privacy.fold_crate(crate);
+ (crate, None)
+}
+
+pub fn collapse_docs(crate: clean::Crate) -> plugins::PluginResult {
+ struct Collapser;
+ impl fold::DocFolder for Collapser {
+ fn fold_item(&mut self, i: Item) -> Option<Item> {
+ let mut docstr = ~"";
+ let mut i = i;
+ for attr in i.attrs.iter() {
+ match *attr {
+ clean::NameValue(~"doc", ref s) => {
+ docstr.push_str(s.clone());
+ docstr.push_char('\n');
+ },
+ _ => ()
+ }
+ }
+ let mut a: ~[clean::Attribute] = i.attrs.iter().filter(|&a| match a {
+ &clean::NameValue(~"doc", _) => false,
+ _ => true
+ }).map(|x| x.clone()).collect();
+ if "" != docstr {
+ a.push(clean::NameValue(~"doc", docstr.trim().to_owned()));
+ }
+ i.attrs = a;
+ self.fold_item_recur(i)
+ }
+ }
+ let mut collapser = Collapser;
+ let crate = collapser.fold_crate(crate);
+ (crate, None)
+}
+
+// n.b. this is copied from src/librustdoc/unindent_pass.rs
+pub fn unindent(s: &str) -> ~str {
+ let lines = s.any_line_iter().collect::<~[&str]>();
+ let mut saw_first_line = false;
+ let mut saw_second_line = false;
+ let min_indent = do lines.iter().fold(uint::max_value) |min_indent, line| {
+
+ // After we see the first non-whitespace line, look at
+ // the line we have. If it is not whitespace, and therefore
+ // part of the first paragraph, then ignore the indentation
+ // level of the first line
+ let ignore_previous_indents =
+ saw_first_line &&
+ !saw_second_line &&
+ !line.is_whitespace();
+
+ let min_indent = if ignore_previous_indents {
+ uint::max_value
+ } else {
+ min_indent
+ };
+
+ if saw_first_line {
+ saw_second_line = true;
+ }
+
+ if line.is_whitespace() {
+ min_indent
+ } else {
+ saw_first_line = true;
+ let mut spaces = 0;
+ do line.iter().all |char| {
+ // Only comparing against space because I wouldn't
+ // know what to do with mixed whitespace chars
+ if char == ' ' {
+ spaces += 1;
+ true
+ } else {
+ false
+ }
+ };
+ num::min(min_indent, spaces)
+ }
+ };
+
+ match lines {
+ [head, .. tail] => {
+ let mut unindented = ~[ head.trim() ];
+ unindented.push_all(do tail.map |&line| {
+ if line.is_whitespace() {
+ line
+ } else {
+ assert!(line.len() >= min_indent);
+ line.slice_from(min_indent)
+ }
+ });
+ unindented.connect("\n")
+ }
+ [] => s.to_owned()
+ }
+}
+
+#[cfg(test)]
+mod unindent_tests {
+ use super::unindent;
+
+ #[test]
+ fn should_unindent() {
+ let s = ~" line1\n line2";
+ let r = unindent(s);
+ assert_eq!(r, ~"line1\nline2");
+ }
+
+ #[test]
+ fn should_unindent_multiple_paragraphs() {
+ let s = ~" line1\n\n line2";
+ let r = unindent(s);
+ assert_eq!(r, ~"line1\n\nline2");
+ }
+
+ #[test]
+ fn should_leave_multiple_indent_levels() {
+ // Line 2 is indented another level beyond the
+ // base indentation and should be preserved
+ let s = ~" line1\n\n line2";
+ let r = unindent(s);
+ assert_eq!(r, ~"line1\n\n line2");
+ }
+
+ #[test]
+ fn should_ignore_first_line_indent() {
+ // Thi first line of the first paragraph may not be indented as
+ // far due to the way the doc string was written:
+ //
+ // #[doc = "Start way over here
+ // and continue here"]
+ let s = ~"line1\n line2";
+ let r = unindent(s);
+ assert_eq!(r, ~"line1\nline2");
+ }
+
+ #[test]
+ fn should_not_ignore_first_line_indent_in_a_single_line_para() {
+ let s = ~"line1\n\n line2";
+ let r = unindent(s);
+ assert_eq!(r, ~"line1\n\n line2");
+ }
+}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Records the full path to items
-
-
-use astsrv;
-use doc::ItemUtils;
-use doc;
-use fold::Fold;
-use fold;
-use pass::Pass;
-
-#[cfg(test)] use extract;
-
-use syntax::ast;
-
-pub fn mk_pass() -> Pass {
- Pass {
- name: ~"path",
- f: run
- }
-}
-
-struct Ctxt {
- srv: astsrv::Srv,
- path: @mut ~[~str]
-}
-
-impl Clone for Ctxt {
- fn clone(&self) -> Ctxt {
- Ctxt {
- srv: self.srv.clone(),
- path: @mut (*self.path).clone()
- }
- }
-}
-
-fn run(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc {
- let ctxt = Ctxt {
- srv: srv,
- path: @mut ~[]
- };
- let fold = Fold {
- ctxt: ctxt.clone(),
- fold_item: fold_item,
- fold_mod: fold_mod,
- fold_nmod: fold_nmod,
- .. fold::default_any_fold(ctxt)
- };
- (fold.fold_doc)(&fold, doc)
-}
-
-fn fold_item(fold: &fold::Fold<Ctxt>, doc: doc::ItemDoc) -> doc::ItemDoc {
- doc::ItemDoc {
- path: (*fold.ctxt.path).clone(),
- .. doc
- }
-}
-
-fn fold_mod(fold: &fold::Fold<Ctxt>, doc: doc::ModDoc) -> doc::ModDoc {
- let is_topmod = doc.id() == ast::CRATE_NODE_ID;
-
- if !is_topmod { fold.ctxt.path.push(doc.name_()); }
- let doc = fold::default_any_fold_mod(fold, doc);
- if !is_topmod { fold.ctxt.path.pop(); }
-
- doc::ModDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- .. doc
- }
-}
-
-fn fold_nmod(fold: &fold::Fold<Ctxt>, doc: doc::NmodDoc) -> doc::NmodDoc {
- fold.ctxt.path.push(doc.name_());
- let doc = fold::default_seq_fold_nmod(fold, doc);
- fold.ctxt.path.pop();
-
- doc::NmodDoc {
- item: (fold.fold_item)(fold, doc.item.clone()),
- .. doc
- }
-}
-
-#[test]
-fn should_record_mod_paths() {
- let source = ~"mod a { mod b { mod c { } } mod d { mod e { } } }";
- do astsrv::from_str(source) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = run(srv.clone(), doc);
- // hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().mods()[1].mods()[0].mods()[0].path(),
- ~[~"a", ~"b"]);
- assert_eq!(doc.cratemod().mods()[1].mods()[1].mods()[0].path(),
- ~[~"a", ~"d"]);
- }
-}
-
-#[test]
-fn should_record_fn_paths() {
- let source = ~"mod a { fn b() { } }";
- do astsrv::from_str(source) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = run(srv.clone(), doc);
- // hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().mods()[1].fns()[0].path(), ~[~"a"]);
- }
-}
--- /dev/null
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use clean;
+
+use extra;
+use dl = std::unstable::dynamic_lib;
+
+pub type PluginJson = Option<(~str, extra::json::Json)>;
+pub type PluginResult = (clean::Crate, PluginJson);
+pub type plugin_callback = extern fn (clean::Crate) -> PluginResult;
+
+/// Manages loading and running of plugins
+pub struct PluginManager {
+ priv dylibs: ~[dl::DynamicLibrary],
+ priv callbacks: ~[plugin_callback],
+ /// The directory plugins will be loaded from
+ prefix: Path,
+}
+
+impl PluginManager {
+ /// Create a new plugin manager
+ pub fn new(prefix: Path) -> PluginManager {
+ PluginManager {
+ dylibs: ~[],
+ callbacks: ~[],
+ prefix: prefix,
+ }
+ }
+
+ /// Load a plugin with the given name.
+ ///
+ /// Turns `name` into the proper dynamic library filename for the given
+ /// platform. On windows, it turns into name.dll, on OS X, name.dylib, and
+ /// elsewhere, libname.so.
+ pub fn load_plugin(&mut self, name: ~str) {
+ let x = self.prefix.push(libname(name));
+ let lib_result = dl::DynamicLibrary::open(Some(&x));
+ let lib = lib_result.unwrap();
+ let plugin = unsafe { lib.symbol("rustdoc_plugin_entrypoint") }.unwrap();
+ self.dylibs.push(lib);
+ self.callbacks.push(plugin);
+ }
+
+ /// Load a normal Rust function as a plugin.
+ ///
+ /// This is to run passes over the cleaned crate. Plugins run this way
+ /// correspond to the A-aux tag on Github.
+ pub fn add_plugin(&mut self, plugin: plugin_callback) {
+ self.callbacks.push(plugin);
+ }
+ /// Run all the loaded plugins over the crate, returning their results
+ pub fn run_plugins(&self, crate: clean::Crate) -> (clean::Crate, ~[PluginJson]) {
+ let mut out_json = ~[];
+ let mut crate = crate;
+ for &callback in self.callbacks.iter() {
+ let (c, res) = callback(crate);
+ crate = c;
+ out_json.push(res);
+ }
+ (crate, out_json)
+ }
+}
+
+#[cfg(target_os="win32")]
+fn libname(mut n: ~str) -> ~str {
+ n.push_str(".dll");
+ n
+}
+
+#[cfg(target_os="macos")]
+fn libname(mut n: ~str) -> ~str {
+ n.push_str(".dylib");
+ n
+}
+
+#[cfg(not(target_os="win32"), not(target_os="macos"))]
+fn libname(n: ~str) -> ~str {
+ let mut i = ~"lib";
+ i.push_str(n);
+ i.push_str(".so");
+ i
+}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Prunes things with the #[doc(hidden)] attribute
-
-use astsrv;
-use attr_parser;
-use doc::ItemUtils;
-use doc;
-use fold::Fold;
-use fold;
-use pass::Pass;
-
-pub fn mk_pass() -> Pass {
- Pass {
- name: ~"prune_hidden",
- f: run
- }
-}
-
-pub fn run(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc {
- let fold = Fold {
- ctxt: srv.clone(),
- fold_mod: fold_mod,
- .. fold::default_any_fold(srv)
- };
- (fold.fold_doc)(&fold, doc)
-}
-
-fn fold_mod(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::ModDoc
-) -> doc::ModDoc {
- let doc = fold::default_any_fold_mod(fold, doc);
-
- doc::ModDoc {
- items: do doc.items.iter().filter |item_tag| {
- !is_hidden(fold.ctxt.clone(), item_tag.item())
- }.map(|x| (*x).clone()).collect(),
- .. doc
- }
-}
-
-fn is_hidden(srv: astsrv::Srv, doc: doc::ItemDoc) -> bool {
- use syntax::ast_map;
-
- let id = doc.id;
- do astsrv::exec(srv) |ctxt| {
- let attrs = match ctxt.ast_map.get_copy(&id) {
- ast_map::node_item(item, _) => item.attrs.clone(),
- _ => ~[]
- };
- attr_parser::parse_hidden(attrs)
- }
-}
-
-#[cfg(test)]
-mod test {
- use astsrv;
- use doc;
- use extract;
- use prune_hidden_pass::run;
-
- fn mk_doc(source: ~str) -> doc::Doc {
- do astsrv::from_str(source.clone()) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- run(srv.clone(), doc)
- }
- }
-
- #[test]
- fn should_prune_hidden_items() {
- let doc = mk_doc(~"#[doc(hidden)] mod a { }");
- assert!(doc.cratemod().mods().is_empty())
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Prune things that are private
-
-
-use extract;
-use syntax::ast;
-use syntax::ast_map;
-use astsrv;
-use doc;
-use fold::Fold;
-use fold;
-use pass::Pass;
-
-pub fn mk_pass() -> Pass {
- Pass {
- name: ~"prune_private",
- f: run
- }
-}
-
-pub fn run(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc {
- // First strip private methods out of impls
- let fold = Fold {
- ctxt: srv.clone(),
- fold_impl: fold_impl,
- .. fold::default_any_fold(srv.clone())
- };
- let doc = (fold.fold_doc)(&fold, doc);
-
- // Then strip private items and empty impls
- let fold = Fold {
- ctxt: srv.clone(),
- fold_mod: fold_mod,
- .. fold::default_any_fold(srv)
- };
- let doc = (fold.fold_doc)(&fold, doc);
-
- return doc;
-}
-
-fn fold_impl(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::ImplDoc
-) -> doc::ImplDoc {
- let doc = fold::default_seq_fold_impl(fold, doc);
-
- do astsrv::exec(fold.ctxt.clone()) |ctxt| {
- match ctxt.ast_map.get_copy(&doc.item.id) {
- ast_map::node_item(item, _) => {
- match item.node {
- ast::item_impl(_, None, _, ref methods) => {
- // Associated impls have complex rules for method visibility
- strip_priv_methods(doc.clone(), *methods, item.vis)
- }
- ast::item_impl(_, Some(_), _ ,_) => {
- // Trait impls don't
- doc.clone()
- }
- _ => fail!()
- }
- }
- _ => fail!()
- }
- }
-}
-
-fn strip_priv_methods(
- doc: doc::ImplDoc,
- methods: &[@ast::method],
- item_vis: ast::visibility
-) -> doc::ImplDoc {
- let methods = do doc.methods.iter().filter |method| {
- let ast_method = do methods.iter().find |m| {
- extract::to_str(m.ident) == method.name
- };
- assert!(ast_method.is_some());
- let ast_method = ast_method.unwrap();
- match ast_method.vis {
- ast::public => true,
- ast::private => false,
- ast::inherited => item_vis == ast::public
- }
- }.map(|x| (*x).clone()).collect();
-
- doc::ImplDoc {
- methods: methods,
- .. doc
- }
-}
-
-fn fold_mod(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::ModDoc
-) -> doc::ModDoc {
- let doc = fold::default_any_fold_mod(fold, doc);
-
- doc::ModDoc {
- items: doc.items.iter().filter(|item_tag| {
- match item_tag {
- & &doc::ImplTag(ref doc) => {
- if doc.trait_types.is_empty() {
- // This is an associated impl. We have already pruned the
- // non-visible methods. If there are any left then
- // retain the impl, otherwise throw it away
- !doc.methods.is_empty()
- } else {
- // This is a trait implementation, make it visible
- // NB: This is not quite right since this could be an impl
- // of a private trait. We can't know that without running
- // resolve though.
- true
- }
- }
- _ => {
- is_visible(fold.ctxt.clone(), item_tag.item())
- }
- }
- }).map(|x| (*x).clone()).collect(),
- .. doc
- }
-}
-
-fn is_visible(srv: astsrv::Srv, doc: doc::ItemDoc) -> bool {
- let id = doc.id;
-
- do astsrv::exec(srv) |ctxt| {
- match ctxt.ast_map.get_copy(&id) {
- ast_map::node_item(item, _) => {
- match &item.node {
- &ast::item_impl(*) => {
- // Impls handled elsewhere
- fail!()
- }
- _ => {
- // Otherwise just look at the visibility
- item.vis == ast::public
- }
- }
- }
- _ => unreachable!()
- }
- }
-}
-
-
-#[cfg(test)]
-mod test {
- use astsrv;
- use doc;
- use extract;
- use tystr_pass;
- use prune_private_pass::run;
-
- fn mk_doc(source: ~str) -> doc::Doc {
- do astsrv::from_str(source.clone()) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = tystr_pass::run(srv.clone(), doc);
- run(srv.clone(), doc)
- }
- }
-
- #[test]
- fn should_prune_items_without_pub_modifier() {
- let doc = mk_doc(~"mod a { }");
- assert!(doc.cratemod().mods().is_empty());
- }
-
- #[test]
- fn should_not_prune_trait_impls() {
- // Impls are more complicated
- let doc = mk_doc(
- ~" \
- trait Foo { } \
- impl Foo for int { } \
- ");
- assert!(!doc.cratemod().impls().is_empty());
- }
-
- #[test]
- fn should_prune_associated_methods_without_vis_modifier_on_impls_without_vis_modifier() {
- let doc = mk_doc(
- ~"impl Foo {\
- pub fn bar() { }\
- fn baz() { }\
- }");
- assert_eq!(doc.cratemod().impls()[0].methods.len(), 1);
- }
-
- #[test]
- fn should_prune_priv_associated_methods_on_impls_without_vis_modifier() {
- let doc = mk_doc(
- ~"impl Foo {\
- pub fn bar() { }\
- fn baz() { }\
- }");
- assert_eq!(doc.cratemod().impls()[0].methods.len(), 1);
- }
-
- #[test]
- fn should_prune_priv_associated_methods_on_pub_impls() {
- let doc = mk_doc(
- ~"impl Foo {\
- pub fn bar() { }\
- fn baz() { }\
- }");
- assert_eq!(doc.cratemod().impls()[0].methods.len(), 1);
- }
-
- #[test]
- fn should_prune_associated_methods_without_vis_modifier_on_priv_impls() {
- let doc = mk_doc(
- ~"impl Foo {\
- pub fn bar() { }\
- fn baz() { }\
- }");
- assert_eq!(doc.cratemod().impls()[0].methods.len(), 1);
- }
-
- #[test]
- fn should_prune_priv_associated_methods_on_priv_impls() {
- let doc = mk_doc(
- ~"impl Foo {\
- pub fn bar() { }\
- fn baz() { }\
- }");
- assert_eq!(doc.cratemod().impls()[0].methods.len(), 1);
- }
-
- #[test]
- fn should_prune_associated_impls_with_no_pub_methods() {
- let doc = mk_doc(
- ~"impl Foo {\
- fn baz() { }\
- }");
- assert!(doc.cratemod().impls().is_empty());
- }
-
- #[test]
- fn should_not_prune_associated_impls_with_pub_methods() {
- let doc = mk_doc(
- ~" \
- impl Foo { pub fn bar() { } } \
- ");
- assert!(!doc.cratemod().impls().is_empty());
- }
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Rustdoc - The Rust documentation generator
-
#[link(name = "rustdoc",
- vers = "0.8-pre",
- uuid = "f8abd014-b281-484d-a0c3-26e3de8e2412",
- url = "https://github.com/mozilla/rust/tree/master/src/rustdoc")];
+ vers = "0.8",
+ uuid = "8c6e4598-1596-4aa5-a24c-b811914bbbc6",
+ url = "https://github.com/mozilla/rust/tree/master/src/librustdoc")];
-#[comment = "The Rust documentation generator"];
+#[desc = "rustdoc, the Rust documentation extractor"];
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
-extern mod extra;
-extern mod rustc;
extern mod syntax;
+extern mod rustc;
+extern mod extra;
-use std::os;
-
-use config::Config;
-use doc::Item;
-use doc::ItemUtils;
-
-pub mod pass;
-pub mod config;
-pub mod parse;
-pub mod extract;
-pub mod attr_parser;
-pub mod doc;
-pub mod markdown_index_pass;
-pub mod markdown_pass;
-pub mod markdown_writer;
+use extra::serialize::Encodable;
+use extra::time;
+use extra::getopts::groups;
+use std::cell::Cell;
+use std::rt::io;
+use std::rt::io::Writer;
+use std::rt::io::file::FileInfo;
+
+pub mod clean;
+pub mod core;
+pub mod doctree;
pub mod fold;
-pub mod path_pass;
-pub mod attr_pass;
-pub mod tystr_pass;
-pub mod prune_hidden_pass;
-pub mod desc_to_brief_pass;
-pub mod text_pass;
-pub mod unindent_pass;
-pub mod trim_pass;
-pub mod astsrv;
-pub mod demo;
-pub mod sort_pass;
-pub mod sort_item_name_pass;
-pub mod sort_item_type_pass;
-pub mod page_pass;
-pub mod sectionalize_pass;
-pub mod escape_pass;
-pub mod prune_private_pass;
+pub mod html {
+ pub mod render;
+ pub mod layout;
+ pub mod markdown;
+ pub mod format;
+}
+pub mod passes;
+pub mod plugins;
+pub mod visit_ast;
+
+pub static SCHEMA_VERSION: &'static str = "0.8.0";
+
+local_data_key!(pub ctxtkey: @core::DocContext)
+
+enum OutputFormat {
+ HTML, JSON
+}
pub fn main() {
- let args = os::args();
- main_args(args);
+ main_args(std::os::args());
+}
+
+pub fn opts() -> ~[groups::OptGroup] {
+ use extra::getopts::groups::*;
+ ~[
+ optmulti("L", "library-path", "directory to add to crate search path",
+ "DIR"),
+ optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
+ optmulti("", "passes", "space separated list of passes to also run",
+ "PASSES"),
+ optmulti("", "plugins", "space separated list of plugins to also load",
+ "PLUGINS"),
+ optflag("h", "help", "show this help message"),
+ optflag("", "nodefaults", "don't run the default passes"),
+ optopt("o", "output", "where to place the output", "PATH"),
+ ]
+}
+
+pub fn usage(argv0: &str) {
+ println(groups::usage(format!("{} [options] [html|json] <crate>",
+ argv0), opts()));
}
pub fn main_args(args: &[~str]) {
- if args.iter().any(|x| "-h" == *x) || args.iter().any(|x| "--help" == *x) {
- config::usage();
+ //use extra::getopts::groups::*;
+
+ let matches = groups::getopts(args.tail(), opts()).unwrap();
+
+ if matches.opt_present("h") || matches.opt_present("help") {
+ usage(args[0]);
return;
}
- let config = match config::parse_config(args) {
- Ok(config) => config,
- Err(err) => {
- printfln!("error: %s", err);
- return;
- }
+ let (format, cratefile) = match matches.free.clone() {
+ [~"json", crate] => (JSON, crate),
+ [~"html", crate] => (HTML, crate),
+ [s, _] => {
+ println!("Unknown output format: `{}`", s);
+ usage(args[0]);
+ exit(1);
+ }
+ [_, .._] => {
+ println!("Expected exactly one crate to process");
+ usage(args[0]);
+ exit(1);
+ }
+ _ => {
+ println!("Expected an output format and then one crate");
+ usage(args[0]);
+ exit(1);
+ }
};
- run(config);
-}
+ // First, parse the crate and extract all relevant information.
+ let libs = Cell::new(matches.opt_strs("L").map(|s| Path(*s)));
+ let cr = Cell::new(Path(cratefile));
+ info2!("starting to run rustc");
+ let crate = do std::task::try {
+ let cr = cr.take();
+ core::run_core(libs.take(), &cr)
+ }.unwrap();
+ info2!("finished with rustc");
+
+ // Process all of the crate attributes, extracting plugin metadata along
+ // with the passes which we are supposed to run.
+ let mut default_passes = !matches.opt_present("nodefaults");
+ let mut passes = matches.opt_strs("passes");
+ let mut plugins = matches.opt_strs("plugins");
+ match crate.module.get_ref().doc_list() {
+ Some(nested) => {
+ for inner in nested.iter() {
+ match *inner {
+ clean::Word(~"no_default_passes") => {
+ default_passes = false;
+ }
+ clean::NameValue(~"passes", ref value) => {
+ for pass in value.word_iter() {
+ passes.push(pass.to_owned());
+ }
+ }
+ clean::NameValue(~"plugins", ref value) => {
+ for p in value.word_iter() {
+ plugins.push(p.to_owned());
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+ None => {}
+ }
+ if default_passes {
+ passes.unshift(~"collapse-docs");
+ passes.unshift(~"unindent-comments");
+ }
-/// Runs rustdoc over the given file
-fn run(config: Config) {
+ // Load all plugins/passes into a PluginManager
+ let mut pm = plugins::PluginManager::new(Path("/tmp/rustdoc_ng/plugins"));
+ for pass in passes.iter() {
+ let plugin = match pass.as_slice() {
+ "strip-hidden" => passes::strip_hidden,
+ "unindent-comments" => passes::unindent_comments,
+ "collapse-docs" => passes::collapse_docs,
+ "collapse-privacy" => passes::collapse_privacy,
+ s => { error!("unknown pass %s, skipping", s); loop },
+ };
+ pm.add_plugin(plugin);
+ }
+ info2!("loading plugins...");
+ for pname in plugins.move_iter() {
+ pm.load_plugin(pname);
+ }
- let source_file = config.input_crate.clone();
+ // Run everything!
+ info2!("Executing passes/plugins");
+ let (crate, res) = pm.run_plugins(crate);
- // Create an AST service from the source code
- do astsrv::from_file(source_file.to_str()) |srv| {
+ info2!("going to format");
+ let started = time::precise_time_ns();
+ let output = matches.opt_str("o").map(|s| Path(*s));
+ match format {
+ HTML => { html::render::run(crate, output.unwrap_or(Path("doc"))) }
+ JSON => { jsonify(crate, res, output.unwrap_or(Path("doc.json"))) }
+ }
+ let ended = time::precise_time_ns();
+ info2!("Took {:.03f}s", (ended as f64 - started as f64) / 1000000000f64);
+}
- // Just time how long it takes for the AST to become available
- do time(~"wait_ast") {
- do astsrv::exec(srv.clone()) |_ctxt| { }
- };
+fn jsonify(crate: clean::Crate, res: ~[plugins::PluginJson], dst: Path) {
+ // {
+ // "schema": version,
+ // "crate": { parsed crate ... },
+ // "plugins": { output of plugins ... }
+ // }
+ let mut json = ~extra::treemap::TreeMap::new();
+ json.insert(~"schema", extra::json::String(SCHEMA_VERSION.to_owned()));
+ let plugins_json = ~res.move_iter().filter_map(|opt| opt).collect();
+
+ // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
+ // straight to the Rust JSON representation.
+ let crate_json_str = do std::io::with_str_writer |w| {
+ crate.encode(&mut extra::json::Encoder(w));
+ };
+ let crate_json = match extra::json::from_str(crate_json_str) {
+ Ok(j) => j,
+ Err(_) => fail!("Rust generated JSON is invalid??")
+ };
- // Extract the initial doc tree from the AST. This contains
- // just names and node ids.
- let doc = time(~"extract", || {
- let default_name = source_file.clone();
- extract::from_srv(srv.clone(), default_name.to_str())
- });
-
- // Refine and publish the document
- pass::run_passes(srv, doc, ~[
- // Generate type and signature strings
- tystr_pass::mk_pass(),
- // Record the full paths to various nodes
- path_pass::mk_pass(),
- // Extract the docs attributes and attach them to doc nodes
- attr_pass::mk_pass(),
- // Perform various text escaping
- escape_pass::mk_pass(),
- // Remove things marked doc(hidden)
- prune_hidden_pass::mk_pass(),
- // Remove things that are private
- prune_private_pass::mk_pass(),
- // Extract brief documentation from the full descriptions
- desc_to_brief_pass::mk_pass(),
- // Massage the text to remove extra indentation
- unindent_pass::mk_pass(),
- // Split text into multiple sections according to headers
- sectionalize_pass::mk_pass(),
- // Trim extra spaces from text
- trim_pass::mk_pass(),
- // Sort items by name
- sort_item_name_pass::mk_pass(),
- // Sort items again by kind
- sort_item_type_pass::mk_pass(),
- // Create indexes appropriate for markdown
- markdown_index_pass::mk_pass(config.clone()),
- // Break the document into pages if required by the
- // output format
- page_pass::mk_pass(config.output_style),
- // Render
- markdown_pass::mk_pass(
- markdown_writer::make_writer_factory(config.clone())
- )
- ]);
- }
+ json.insert(~"crate", crate_json);
+ json.insert(~"plugins", extra::json::Object(plugins_json));
+
+ let mut file = dst.open_writer(io::Create).unwrap();
+ let output = extra::json::Object(json).to_str();
+ file.write(output.as_bytes());
}
-pub fn time<T>(what: ~str, f: &fn() -> T) -> T {
- let start = extra::time::precise_time_s();
- let rv = f();
- let end = extra::time::precise_time_s();
- info!("time: %3.3f s %s", end - start, what);
- rv
+fn exit(status: int) -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+ use std::libc;
+ unsafe { libc::exit(status as libc::c_int) }
}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Breaks rustdocs into sections according to their headers
-
-
-use astsrv;
-use doc::ItemUtils;
-use doc;
-use fold::Fold;
-use fold;
-use pass::Pass;
-
-pub fn mk_pass() -> Pass {
- Pass {
- name: ~"sectionalize",
- f: run
- }
-}
-
-pub fn run(_srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc {
- let fold = Fold {
- fold_item: fold_item,
- fold_trait: fold_trait,
- fold_impl: fold_impl,
- .. fold::default_any_fold(())
- };
- (fold.fold_doc)(&fold, doc)
-}
-
-fn fold_item(fold: &fold::Fold<()>, doc: doc::ItemDoc) -> doc::ItemDoc {
- let doc = fold::default_seq_fold_item(fold, doc);
- let (desc, sections) = sectionalize(doc.desc.clone());
-
- doc::ItemDoc {
- desc: desc,
- sections: sections,
- .. doc
- }
-}
-
-fn fold_trait(fold: &fold::Fold<()>, doc: doc::TraitDoc) -> doc::TraitDoc {
- let doc = fold::default_seq_fold_trait(fold, doc);
-
- doc::TraitDoc {
- methods: do doc.methods.map |method| {
- let (desc, sections) = sectionalize(method.desc.clone());
-
- doc::MethodDoc {
- desc: desc,
- sections: sections,
- .. (*method).clone()
- }
- },
- .. doc
- }
-}
-
-fn fold_impl(fold: &fold::Fold<()>, doc: doc::ImplDoc) -> doc::ImplDoc {
- let doc = fold::default_seq_fold_impl(fold, doc);
-
- doc::ImplDoc {
- methods: do doc.methods.map |method| {
- let (desc, sections) = sectionalize(method.desc.clone());
-
- doc::MethodDoc {
- desc: desc,
- sections: sections,
- .. (*method).clone()
- }
- },
- .. doc
- }
-}
-
-fn sectionalize(desc: Option<~str>) -> (Option<~str>, ~[doc::Section]) {
-
- /*!
- * Take a description of the form
- *
- * General text
- *
- * # Section header
- *
- * Section text
- *
- * # Section header
- *
- * Section text
- *
- * and remove each header and accompanying text into section records.
- */
-
- if desc.is_none() {
- return (None, ~[]);
- }
-
- let mut new_desc = None::<~str>;
- let mut current_section: Option<doc::Section> = None;
- let mut sections = ~[];
-
- for line in desc.get_ref().any_line_iter() {
- match parse_header(line) {
- Some(header) => {
- if current_section.is_some() {
- sections.push((*current_section.get_ref()).clone());
- }
- current_section = Some(doc::Section {
- header: header.to_owned(),
- body: ~""
- });
- }
- None => {
- match current_section.clone() {
- Some(section) => {
- current_section = Some(doc::Section {
- body: fmt!("%s\n%s", section.body, line),
- .. section
- });
- }
- None => {
- new_desc = match new_desc.clone() {
- Some(desc) => {
- Some(fmt!("%s\n%s", desc, line))
- }
- None => {
- Some(line.to_owned())
- }
- };
- }
- }
- }
- }
- }
-
- if current_section.is_some() {
- sections.push(current_section.unwrap());
- }
-
- (new_desc, sections)
-}
-
-fn parse_header<'a>(line: &'a str) -> Option<&'a str> {
- if line.starts_with("# ") {
- Some(line.slice_from(2))
- } else {
- None
- }
-}
-
-
-
-#[cfg(test)]
-mod test {
-
- use astsrv;
- use attr_pass;
- use doc;
- use extract;
- use prune_hidden_pass;
- use sectionalize_pass::run;
-
- fn mk_doc(source: ~str) -> doc::Doc {
- do astsrv::from_str(source.clone()) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
- let doc = (prune_hidden_pass::mk_pass().f)(srv.clone(), doc);
- run(srv.clone(), doc)
- }
- }
-
- #[test]
- fn should_create_section_headers() {
- let doc = mk_doc(
- ~"#[doc = \"\
- # Header\n\
- Body\"]\
- mod a {
-}");
- assert!(doc.cratemod().mods()[0].item.sections[0].header.contains("Header"));
- }
-
- #[test]
- fn should_create_section_bodies() {
- let doc = mk_doc(
- ~"#[doc = \"\
- # Header\n\
- Body\"]\
- mod a {
-}");
- assert!(doc.cratemod().mods()[0].item.sections[0].body.contains("Body"));
- }
-
- #[test]
- fn should_not_create_sections_from_indented_headers() {
- let doc = mk_doc(
- ~"#[doc = \"\n\
- Text\n # Header\n\
- Body\"]\
- mod a {
-}");
- assert!(doc.cratemod().mods()[0].item.sections.is_empty());
- }
-
- #[test]
- fn should_remove_section_text_from_main_desc() {
- let doc = mk_doc(
- ~"#[doc = \"\
- Description\n\n\
- # Header\n\
- Body\"]\
- mod a {
-}");
- assert!(!doc.cratemod().mods()[0].desc().unwrap().contains("Header"));
- assert!(!doc.cratemod().mods()[0].desc().unwrap().contains("Body"));
- }
-
- #[test]
- fn should_eliminate_desc_if_it_is_just_whitespace() {
- let doc = mk_doc(
- ~"#[doc = \"\
- # Header\n\
- Body\"]\
- mod a {
-}");
- assert_eq!(doc.cratemod().mods()[0].desc(), None);
- }
-
- #[test]
- fn should_sectionalize_trait_methods() {
- let doc = mk_doc(
- ~"trait i {
-#[doc = \"\
- # Header\n\
- Body\"]\
- fn a(); }");
- assert_eq!(doc.cratemod().traits()[0].methods[0].sections.len(), 1u);
- }
-
- #[test]
- fn should_sectionalize_impl_methods() {
- let doc = mk_doc(
- ~"impl bool {
-#[doc = \"\
- # Header\n\
- Body\"]\
- fn a() { } }");
- assert_eq!(doc.cratemod().impls()[0].methods[0].sections.len(), 1u);
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Sorts items by name
-
-use doc::ItemUtils;
-use doc;
-use pass::Pass;
-use sort_pass;
-
-pub fn mk_pass() -> Pass {
- fn by_item_name(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool {
- (*item1).name_() <= (*item2).name_()
- }
- sort_pass::mk_pass(~"sort_item_name", by_item_name)
-}
-
-#[test]
-fn test() {
- use astsrv;
- use extract;
-
- let source = ~"mod z { } fn y() { }";
- do astsrv::from_str(source) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = (mk_pass().f)(srv.clone(), doc);
- // hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().items[1].name_(), ~"y");
- assert_eq!(doc.cratemod().items[2].name_(), ~"z");
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Sorts items by type
-
-use doc;
-use pass::Pass;
-use sort_pass;
-
-pub fn mk_pass() -> Pass {
- fn by_score(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool {
- fn score(item: &doc::ItemTag) -> int {
- match *item {
- doc::StaticTag(_) => 0,
- doc::TyTag(_) => 1,
- doc::EnumTag(_) => 2,
- doc::StructTag(_) => 3,
- doc::TraitTag(_) => 4,
- doc::ImplTag(_) => 5,
- doc::FnTag(_) => 6,
- doc::ModTag(_) => 7,
- doc::NmodTag(_) => 8
- }
- }
-
- score(item1) <= score(item2)
- }
-
- sort_pass::mk_pass(~"sort_item_type", by_score)
-}
-
-#[test]
-fn test() {
- use astsrv;
- use extract;
-
- let source =
- ~"mod imod { } \
- static istatic: int = 0; \
- fn ifn() { } \
- enum ienum { ivar } \
- trait itrait { fn a(); } \
- impl int { fn a() { } } \
- type itype = int; \
- struct istruct { f: () }";
- do astsrv::from_str(source) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = (mk_pass().f)(srv.clone(), doc);
- // hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().items[0].name_(), ~"istatic");
- assert_eq!(doc.cratemod().items[1].name_(), ~"itype");
- assert_eq!(doc.cratemod().items[2].name_(), ~"ienum");
- assert_eq!(doc.cratemod().items[3].name_(), ~"istruct");
- assert_eq!(doc.cratemod().items[4].name_(), ~"itrait");
- assert_eq!(doc.cratemod().items[5].name_(), ~"__extensions__");
- assert_eq!(doc.cratemod().items[6].name_(), ~"ifn");
- // hidden __std_macros module fits here.
- assert_eq!(doc.cratemod().items[8].name_(), ~"imod");
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A general sorting pass
-
-use astsrv;
-use doc;
-use fold::Fold;
-use fold;
-use pass::Pass;
-
-#[cfg(test)] use extract;
-
-use extra::sort;
-use std::clone::Clone;
-
-pub type ItemLtEqOp = @fn(v1: &doc::ItemTag, v2: &doc::ItemTag) -> bool;
-
-struct ItemLtEq {
- op: ItemLtEqOp,
-}
-
-impl Clone for ItemLtEq {
- fn clone(&self) -> ItemLtEq {
- ItemLtEq {
- op: self.op,
- }
- }
-}
-
-pub fn mk_pass(name: ~str, lteq: ItemLtEqOp) -> Pass {
- Pass {
- name: name.clone(),
- f: |srv, doc| run(srv, doc, ItemLtEq { op: lteq })
- }
-}
-
-fn run(
- _srv: astsrv::Srv,
- doc: doc::Doc,
- lteq: ItemLtEq
-) -> doc::Doc {
- let fold = Fold {
- fold_mod: fold_mod,
- .. fold::default_any_fold(lteq)
- };
- (fold.fold_doc)(&fold, doc)
-}
-
-fn fold_mod(
- fold: &fold::Fold<ItemLtEq>,
- doc: doc::ModDoc
-) -> doc::ModDoc {
- let doc = fold::default_any_fold_mod(fold, doc);
- doc::ModDoc {
- items: sort::merge_sort(doc.items, fold.ctxt.op),
- .. doc
- }
-}
-
-#[test]
-fn test() {
- fn name_lteq(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool {
- (*item1).name_() <= (*item2).name_()
- }
-
- let source = ~"mod z { mod y { } fn x() { } } mod w { }";
- do astsrv::from_str(source) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = (mk_pass(~"", name_lteq).f)(srv.clone(), doc);
- // hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().mods()[1].name_(), ~"w");
- assert_eq!(doc.cratemod().mods()[2].items[0].name_(), ~"x");
- assert_eq!(doc.cratemod().mods()[2].items[1].name_(), ~"y");
- assert_eq!(doc.cratemod().mods()[2].name_(), ~"z");
- }
-}
-
-#[test]
-fn should_be_stable() {
- fn always_eq(_item1: &doc::ItemTag, _item2: &doc::ItemTag) -> bool {
- true
- }
-
- let source = ~"mod a { mod b { } } mod c { mod d { } }";
- do astsrv::from_str(source) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = (mk_pass(~"", always_eq).f)(srv.clone(), doc);
- // hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().mods()[1].items[0].name_(), ~"b");
- assert_eq!(doc.cratemod().mods()[2].items[0].name_(), ~"d");
- let doc = (mk_pass(~"", always_eq).f)(srv.clone(), doc);
- assert_eq!(doc.cratemod().mods()[1].items[0].name_(), ~"b");
- assert_eq!(doc.cratemod().mods()[2].items[0].name_(), ~"d");
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Generic pass for performing an operation on all descriptions
-
-
-use astsrv;
-use doc::ItemUtils;
-use doc;
-use fold::Fold;
-use fold;
-use pass::Pass;
-
-use std::cell::Cell;
-
-pub fn mk_pass(name: ~str, op: @fn(&str) -> ~str) -> Pass {
- let op = Cell::new(op);
- Pass {
- name: name.clone(),
- f: |srv: astsrv::Srv, doc: doc::Doc| -> doc::Doc {
- run(srv, doc, op.take())
- }
- }
-}
-
-type Op = @fn(&str) -> ~str;
-
-struct WrappedOp {
- op: Op,
-}
-
-impl Clone for WrappedOp {
- fn clone(&self) -> WrappedOp {
- WrappedOp {
- op: self.op,
- }
- }
-}
-
-fn run(
- _srv: astsrv::Srv,
- doc: doc::Doc,
- op: Op
-) -> doc::Doc {
- let op = WrappedOp {
- op: op
- };
- let fold = Fold {
- fold_item: fold_item,
- fold_enum: fold_enum,
- fold_trait: fold_trait,
- fold_impl: fold_impl,
- .. fold::default_any_fold(op)
- };
- (fold.fold_doc)(&fold, doc)
-}
-
-fn maybe_apply_op(op: WrappedOp, s: &Option<~str>) -> Option<~str> {
- s.map(|s| (op.op)(*s) )
-}
-
-fn fold_item(fold: &fold::Fold<WrappedOp>, doc: doc::ItemDoc)
- -> doc::ItemDoc {
- let doc = fold::default_seq_fold_item(fold, doc);
-
- doc::ItemDoc {
- brief: maybe_apply_op(fold.ctxt, &doc.brief),
- desc: maybe_apply_op(fold.ctxt, &doc.desc),
- sections: apply_to_sections(fold.ctxt, doc.sections.clone()),
- .. doc
- }
-}
-
-fn apply_to_sections(op: WrappedOp, sections: ~[doc::Section])
- -> ~[doc::Section] {
- sections.map(|section| doc::Section {
- header: (op.op)(section.header.clone()),
- body: (op.op)(section.body.clone())
- })
-}
-
-fn fold_enum(fold: &fold::Fold<WrappedOp>, doc: doc::EnumDoc)
- -> doc::EnumDoc {
- let doc = fold::default_seq_fold_enum(fold, doc);
- let fold_copy = *fold;
-
- doc::EnumDoc {
- variants: do doc.variants.map |variant| {
- doc::VariantDoc {
- desc: maybe_apply_op(fold_copy.ctxt, &variant.desc),
- .. (*variant).clone()
- }
- },
- .. doc
- }
-}
-
-fn fold_trait(fold: &fold::Fold<WrappedOp>, doc: doc::TraitDoc)
- -> doc::TraitDoc {
- let doc = fold::default_seq_fold_trait(fold, doc);
-
- doc::TraitDoc {
- methods: apply_to_methods(fold.ctxt, doc.methods.clone()),
- .. doc
- }
-}
-
-fn apply_to_methods(op: WrappedOp, docs: ~[doc::MethodDoc])
- -> ~[doc::MethodDoc] {
- do docs.map |doc| {
- doc::MethodDoc {
- brief: maybe_apply_op(op, &doc.brief),
- desc: maybe_apply_op(op, &doc.desc),
- sections: apply_to_sections(op, doc.sections.clone()),
- .. (*doc).clone()
- }
- }
-}
-
-fn fold_impl(fold: &fold::Fold<WrappedOp>, doc: doc::ImplDoc)
- -> doc::ImplDoc {
- let doc = fold::default_seq_fold_impl(fold, doc);
-
- doc::ImplDoc {
- methods: apply_to_methods(fold.ctxt, doc.methods.clone()),
- .. doc
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use astsrv;
- use attr_pass;
- use desc_to_brief_pass;
- use doc;
- use extract;
- use sectionalize_pass;
- use text_pass::mk_pass;
-
- fn mk_doc(source: ~str) -> doc::Doc {
- do astsrv::from_str(source.clone()) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
- let doc = (desc_to_brief_pass::mk_pass().f)(srv.clone(), doc);
- let doc = (sectionalize_pass::mk_pass().f)(srv.clone(), doc);
- (mk_pass(~"", |s| s.trim().to_owned() ).f)(srv.clone(), doc)
- }
- }
-
- #[test]
- fn should_execute_op_on_enum_brief() {
- let doc = mk_doc(~"#[doc = \" a \"] enum a { b }");
- assert_eq!(doc.cratemod().enums()[0].brief(), Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_enum_desc() {
- let doc = mk_doc(~"#[doc = \" a \"] enum a { b }");
- assert_eq!(doc.cratemod().enums()[0].desc(), Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_variant_desc() {
- let doc = mk_doc(~"enum a { #[doc = \" a \"] b }");
- assert!(doc.cratemod().enums()[0].variants[0].desc == Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_trait_brief() {
- let doc = mk_doc(
- ~"#[doc = \" a \"] trait i { fn a(); }");
- assert_eq!(doc.cratemod().traits()[0].brief(), Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_trait_desc() {
- let doc = mk_doc(
- ~"#[doc = \" a \"] trait i { fn a(); }");
- assert_eq!(doc.cratemod().traits()[0].desc(), Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_trait_method_brief() {
- let doc = mk_doc(
- ~"trait i { #[doc = \" a \"] fn a(); }");
- assert!(doc.cratemod().traits()[0].methods[0].brief == Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_trait_method_desc() {
- let doc = mk_doc(
- ~"trait i { #[doc = \" a \"] fn a(); }");
- assert!(doc.cratemod().traits()[0].methods[0].desc == Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_impl_brief() {
- let doc = mk_doc(
- ~"#[doc = \" a \"] impl int { fn a() { } }");
- assert_eq!(doc.cratemod().impls()[0].brief(), Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_impl_desc() {
- let doc = mk_doc(
- ~"#[doc = \" a \"] impl int { fn a() { } }");
- assert_eq!(doc.cratemod().impls()[0].desc(), Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_impl_method_brief() {
- let doc = mk_doc(
- ~"impl int { #[doc = \" a \"] fn a() { } }");
- assert!(doc.cratemod().impls()[0].methods[0].brief == Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_impl_method_desc() {
- let doc = mk_doc(
- ~"impl int { #[doc = \" a \"] fn a() { } }");
- assert!(doc.cratemod().impls()[0].methods[0].desc == Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_type_brief() {
- let doc = mk_doc(
- ~"#[doc = \" a \"] type t = int;");
- assert_eq!(doc.cratemod().types()[0].brief(), Some(~"a"));
- }
-
- #[test]
- fn should_execute_op_on_type_desc() {
- let doc = mk_doc(
- ~"#[doc = \" a \"] type t = int;");
- assert_eq!(doc.cratemod().types()[0].desc(), Some(~"a"));
- }
-
- #[test]
- fn should_execute_on_item_section_headers() {
- let doc = mk_doc(
- ~"#[doc = \"\
- # Header \n\
- Body\"]\
- fn a() { }");
- assert!(doc.cratemod().fns()[0].sections()[0].header == ~"Header");
- }
-
- #[test]
- fn should_execute_on_item_section_bodies() {
- let doc = mk_doc(
- ~"#[doc = \"\
- # Header\n\
- Body \"]\
- fn a() { }");
- assert!(doc.cratemod().fns()[0].sections()[0].body == ~"Body");
- }
-
- #[test]
- fn should_execute_on_trait_method_section_headers() {
- let doc = mk_doc(
- ~"trait i {
-#[doc = \"\
- # Header \n\
- Body\"]\
- fn a(); }");
- assert!(doc.cratemod().traits()[0].methods[0].sections[0].header
- == ~"Header");
- }
-
- #[test]
- fn should_execute_on_trait_method_section_bodies() {
- let doc = mk_doc(
- ~"trait i {
-#[doc = \"\
- # Header\n\
- Body \"]\
- fn a(); }");
- assert!(doc.cratemod().traits()[0].methods[0].sections[0].body ==
- ~"Body");
- }
-
- #[test]
- fn should_execute_on_impl_method_section_headers() {
- let doc = mk_doc(
- ~"impl bool {
-#[doc = \"\
- # Header \n\
- Body\"]\
- fn a() { } }");
- assert!(doc.cratemod().impls()[0].methods[0].sections[0].header
- == ~"Header");
- }
-
- #[test]
- fn should_execute_on_impl_method_section_bodies() {
- let doc = mk_doc(
- ~"impl bool {
-#[doc = \"\
- # Header\n\
- Body \"]\
- fn a() { } }");
- assert!(doc.cratemod().impls()[0].methods[0].sections[0].body ==
- ~"Body");
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-Pulls a brief description out of a long description.
-
-If the first paragraph of a long description is short enough then it
-is interpreted as the brief description.
-*/
-
-use pass::Pass;
-use text_pass;
-
-pub fn mk_pass() -> Pass {
- text_pass::mk_pass(~"trim", |s| s.trim().to_owned() )
-}
-
-#[cfg(test)]
-mod test {
- use astsrv;
- use attr_pass;
- use doc;
- use extract;
- use prune_hidden_pass;
- use trim_pass::mk_pass;
-
- fn mk_doc(source: ~str) -> doc::Doc {
- do astsrv::from_str(source.clone()) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- let doc = (attr_pass::mk_pass().f)(srv.clone(), doc);
- let doc = (prune_hidden_pass::mk_pass().f)(srv.clone(), doc);
- (mk_pass().f)(srv.clone(), doc)
- }
- }
-
- #[test]
- fn should_trim_text() {
- use std::option::Some;
-
- let doc = mk_doc(~"#[doc = \" desc \"] \
- mod m {
-}");
- assert_eq!(doc.cratemod().mods()[0].desc(), Some(~"desc"));
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Pulls type information out of the AST and attaches it to the document
-
-
-use astsrv;
-use doc::ItemUtils;
-use doc;
-use extract::to_str;
-use extract;
-use fold::Fold;
-use fold;
-use pass::Pass;
-
-use syntax::ast;
-use syntax::print::pprust;
-use syntax::parse::token;
-use syntax::ast_map;
-
-pub fn mk_pass() -> Pass {
- Pass {
- name: ~"tystr",
- f: run
- }
-}
-
-pub fn run(
- srv: astsrv::Srv,
- doc: doc::Doc
-) -> doc::Doc {
- let fold = Fold {
- ctxt: srv.clone(),
- fold_fn: fold_fn,
- fold_static: fold_static,
- fold_enum: fold_enum,
- fold_trait: fold_trait,
- fold_impl: fold_impl,
- fold_type: fold_type,
- fold_struct: fold_struct,
- .. fold::default_any_fold(srv)
- };
- (fold.fold_doc)(&fold, doc)
-}
-
-fn fold_fn(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::FnDoc
-) -> doc::FnDoc {
-
- let srv = fold.ctxt.clone();
-
- doc::SimpleItemDoc {
- sig: get_fn_sig(srv, doc.id()),
- .. doc
- }
-}
-
-fn get_fn_sig(srv: astsrv::Srv, fn_id: doc::AstId) -> Option<~str> {
- do astsrv::exec(srv) |ctxt| {
- match ctxt.ast_map.get_copy(&fn_id) {
- ast_map::node_item(@ast::item {
- ident: ident,
- node: ast::item_fn(ref decl, purity, _, ref tys, _), _
- }, _) => {
- Some(pprust::fun_to_str(decl,
- purity,
- ident,
- None,
- tys,
- token::get_ident_interner()))
- }
- ast_map::node_foreign_item(@ast::foreign_item {
- ident: ident,
- node: ast::foreign_item_fn(ref decl, ref tys), _
- }, _, _, _) => {
- Some(pprust::fun_to_str(decl,
- ast::impure_fn,
- ident,
- None,
- tys,
- token::get_ident_interner()))
- }
- _ => fail!("get_fn_sig: fn_id not bound to a fn item")
- }
- }
-}
-
-fn fold_static(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::StaticDoc
-) -> doc::StaticDoc {
- let srv = fold.ctxt.clone();
-
- doc::SimpleItemDoc {
- sig: Some({
- let doc = doc.clone();
- do astsrv::exec(srv) |ctxt| {
- match ctxt.ast_map.get_copy(&doc.id()) {
- ast_map::node_item(@ast::item {
- node: ast::item_static(ref ty, _, _), _
- }, _) => {
- pprust::ty_to_str(ty, extract::interner())
- }
- _ => fail!("fold_static: id not bound to a static item")
- }
- }}),
- .. doc
- }
-}
-
-fn fold_enum(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::EnumDoc
-) -> doc::EnumDoc {
- let doc_id = doc.id();
- let srv = fold.ctxt.clone();
-
- doc::EnumDoc {
- variants: do doc.variants.iter().map |variant| {
- let sig = {
- let variant = (*variant).clone();
- do astsrv::exec(srv.clone()) |ctxt| {
- match ctxt.ast_map.get_copy(&doc_id) {
- ast_map::node_item(@ast::item {
- node: ast::item_enum(ref enum_definition, _), _
- }, _) => {
- let ast_variant =
- (*do enum_definition.variants.iter().find |v| {
- to_str(v.node.name) == variant.name
- }.unwrap()).clone();
-
- pprust::variant_to_str(
- &ast_variant, extract::interner())
- }
- _ => fail!("enum variant not bound to an enum item")
- }
- }
- };
-
- doc::VariantDoc {
- sig: Some(sig),
- .. (*variant).clone()
- }
- }.collect(),
- .. doc
- }
-}
-
-fn fold_trait(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::TraitDoc
-) -> doc::TraitDoc {
- doc::TraitDoc {
- methods: merge_methods(fold.ctxt.clone(), doc.id(), doc.methods.clone()),
- .. doc
- }
-}
-
-fn merge_methods(
- srv: astsrv::Srv,
- item_id: doc::AstId,
- docs: ~[doc::MethodDoc]
-) -> ~[doc::MethodDoc] {
- do docs.iter().map |doc| {
- doc::MethodDoc {
- sig: get_method_sig(srv.clone(), item_id, doc.name.clone()),
- .. (*doc).clone()
- }
- }.collect()
-}
-
-fn get_method_sig(
- srv: astsrv::Srv,
- item_id: doc::AstId,
- method_name: ~str
-) -> Option<~str> {
- do astsrv::exec(srv) |ctxt| {
- match ctxt.ast_map.get_copy(&item_id) {
- ast_map::node_item(@ast::item {
- node: ast::item_trait(_, _, ref methods), _
- }, _) => {
- match methods.iter().find(|&method| {
- match (*method).clone() {
- ast::required(ty_m) => to_str(ty_m.ident) == method_name,
- ast::provided(m) => to_str(m.ident) == method_name,
- }
- }) {
- Some(method) => {
- match (*method).clone() {
- ast::required(ty_m) => {
- Some(pprust::fun_to_str(
- &ty_m.decl,
- ty_m.purity,
- ty_m.ident,
- Some(ty_m.explicit_self.node),
- &ty_m.generics,
- extract::interner()
- ))
- }
- ast::provided(m) => {
- Some(pprust::fun_to_str(
- &m.decl,
- m.purity,
- m.ident,
- Some(m.explicit_self.node),
- &m.generics,
- extract::interner()
- ))
- }
- }
- }
- _ => fail!("method not found")
- }
- }
- ast_map::node_item(@ast::item {
- node: ast::item_impl(_, _, _, ref methods), _
- }, _) => {
- match methods.iter().find(|method| {
- to_str(method.ident) == method_name
- }) {
- Some(method) => {
- Some(pprust::fun_to_str(
- &method.decl,
- method.purity,
- method.ident,
- Some(method.explicit_self.node),
- &method.generics,
- extract::interner()
- ))
- }
- None => fail!("method not found")
- }
- }
- _ => fail!("get_method_sig: item ID not bound to trait or impl")
- }
- }
-}
-
-fn fold_impl(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::ImplDoc
-) -> doc::ImplDoc {
-
- let srv = fold.ctxt.clone();
-
- let (bounds, trait_types, self_ty) = {
- let doc = doc.clone();
- do astsrv::exec(srv) |ctxt| {
- match ctxt.ast_map.get_copy(&doc.id()) {
- ast_map::node_item(@ast::item {
- node: ast::item_impl(ref generics, ref opt_trait_type, ref self_ty, _), _
- }, _) => {
- let bounds = pprust::generics_to_str(generics, extract::interner());
- let bounds = if bounds.is_empty() { None } else { Some(bounds) };
- let trait_types = do opt_trait_type.map_default(~[]) |p| {
- ~[pprust::path_to_str(&p.path, extract::interner())]
- };
- (bounds,
- trait_types,
- Some(pprust::ty_to_str(
- self_ty, extract::interner())))
- }
- _ => fail!("expected impl")
- }
- }
- };
-
- doc::ImplDoc {
- bounds_str: bounds,
- trait_types: trait_types,
- self_ty: self_ty,
- methods: merge_methods(fold.ctxt.clone(), doc.id(), doc.methods.clone()),
- .. doc
- }
-}
-
-fn fold_type(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::TyDoc
-) -> doc::TyDoc {
-
- let srv = fold.ctxt.clone();
-
- doc::SimpleItemDoc {
- sig: {
- let doc = doc.clone();
- do astsrv::exec(srv) |ctxt| {
- match ctxt.ast_map.get_copy(&doc.id()) {
- ast_map::node_item(@ast::item {
- ident: ident,
- node: ast::item_ty(ref ty, ref params), _
- }, _) => {
- Some(fmt!(
- "type %s%s = %s",
- to_str(ident),
- pprust::generics_to_str(params,
- extract::interner()),
- pprust::ty_to_str(ty, extract::interner())
- ))
- }
- _ => fail!("expected type")
- }
- }
- },
- .. doc
- }
-}
-
-fn fold_struct(
- fold: &fold::Fold<astsrv::Srv>,
- doc: doc::StructDoc
-) -> doc::StructDoc {
- let srv = fold.ctxt.clone();
-
- doc::StructDoc {
- sig: {
- let doc = doc.clone();
- do astsrv::exec(srv) |ctxt| {
- match ctxt.ast_map.get_copy(&doc.id()) {
- ast_map::node_item(item, _) => {
- let item = strip_struct_extra_stuff(item);
- Some(pprust::item_to_str(item,
- extract::interner()))
- }
- _ => fail!("not an item")
- }
- }
- },
- .. doc
- }
-}
-
-/// Removes various things from the struct item definition that
-/// shouldn't be displayed in the struct signature. Probably there
-/// should be a simple pprust::struct_to_str function that does
-/// what I actually want
-fn strip_struct_extra_stuff(item: @ast::item) -> @ast::item {
- let node = match item.node.clone() {
- ast::item_struct(def, tys) => ast::item_struct(def, tys),
- _ => fail!("not a struct")
- };
-
- @ast::item {
- attrs: ~[], // Remove the attributes
- node: node,
- .. (*item).clone()
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use astsrv;
- use doc;
- use extract;
- use tystr_pass::run;
-
- fn mk_doc(source: ~str) -> doc::Doc {
- do astsrv::from_str(source.clone()) |srv| {
- let doc = extract::from_srv(srv.clone(), ~"");
- run(srv.clone(), doc)
- }
- }
-
- #[test]
- fn should_add_fn_sig() {
- let doc = mk_doc(~"fn a<T>() -> int { }");
- assert!(doc.cratemod().fns()[0].sig == Some(~"fn a<T>() -> int"));
- }
-
- #[test]
- fn should_add_foreign_fn_sig() {
- let doc = mk_doc(~"extern { fn a<T>() -> int; }");
- assert!(doc.cratemod().nmods()[0].fns[0].sig ==
- Some(~"fn a<T>() -> int"));
- }
-
- #[test]
- fn should_add_static_types() {
- let doc = mk_doc(~"static a: bool = true;");
- assert!(doc.cratemod().statics()[0].sig == Some(~"bool"));
- }
-
- #[test]
- fn should_add_variant_sigs() {
- let doc = mk_doc(~"enum a { b(int) }");
- assert!(doc.cratemod().enums()[0].variants[0].sig ==
- Some(~"b(int)"));
- }
-
- #[test]
- fn should_add_trait_method_sigs() {
- let doc = mk_doc(~"trait i { fn a<T>(&mut self) -> int; }");
- assert!(doc.cratemod().traits()[0].methods[0].sig
- == Some(~"fn a<T>(&mut self) -> int"));
- }
-
- #[test]
- fn should_add_impl_bounds() {
- let doc = mk_doc(~"impl<T, U, V: Clone> Option<T, U, V> { }");
- assert!(doc.cratemod().impls()[0].bounds_str == Some(~"<T, U, V: Clone>"));
- }
-
- #[test]
- fn should_add_impl_trait_types() {
- let doc = mk_doc(~"impl j for int { fn a<T>() { } }");
- assert!(doc.cratemod().impls()[0].trait_types[0] == ~"j");
- }
-
- #[test]
- fn should_not_add_impl_trait_types_if_none() {
- let doc = mk_doc(~"impl int { fn a() { } }");
- assert!(doc.cratemod().impls()[0].trait_types.len() == 0);
- }
-
- #[test]
- fn should_add_impl_self_ty() {
- let doc = mk_doc(~"impl int { fn a() { } }");
- assert!(doc.cratemod().impls()[0].self_ty == Some(~"int"));
- }
-
- #[test]
- fn should_add_impl_method_sigs() {
- let doc = mk_doc(~"impl int { fn a<T>(&self) -> int { fail!() } }");
- assert!(doc.cratemod().impls()[0].methods[0].sig
- == Some(~"fn a<T>(&self) -> int"));
- }
-
- #[test]
- fn should_add_type_signatures() {
- let doc = mk_doc(~"type t<T> = int;");
- assert!(doc.cratemod().types()[0].sig == Some(~"type t<T> = int"));
- }
-
- #[test]
- fn should_add_struct_defs() {
- let doc = mk_doc(~"struct S { field: () }");
- assert!(doc.cratemod().structs()[0].sig.unwrap().contains(
- "struct S {"));
- }
-
- #[test]
- fn should_not_serialize_struct_attrs() {
- // All we care about are the fields
- let doc = mk_doc(~"#[wut] struct S { field: () }");
- assert!(!doc.cratemod().structs()[0].sig.unwrap().contains("wut"));
- }
-}
+++ /dev/null
-// Copyright 2012-2013 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.
-
-/*!
-Removes the common level of indention from description strings. For
-instance, if an entire doc comment is indented 8 spaces we want to
-remove those 8 spaces from every line.
-
-The first line of a string is allowed to be intend less than
-subsequent lines in the same paragraph in order to account for
-instances where the string containing the doc comment is opened in the
-middle of a line, and each of the following lines is indented.
-*/
-
-
-use std::num;
-use std::uint;
-use pass::Pass;
-use text_pass;
-
-pub fn mk_pass() -> Pass {
- text_pass::mk_pass(~"unindent", unindent)
-}
-
-fn unindent(s: &str) -> ~str {
- let lines = s.any_line_iter().collect::<~[&str]>();
- let mut saw_first_line = false;
- let mut saw_second_line = false;
- let min_indent = do lines.iter().fold(uint::max_value)
- |min_indent, line| {
-
- // After we see the first non-whitespace line, look at
- // the line we have. If it is not whitespace, and therefore
- // part of the first paragraph, then ignore the indentation
- // level of the first line
- let ignore_previous_indents =
- saw_first_line &&
- !saw_second_line &&
- !line.is_whitespace();
-
- let min_indent = if ignore_previous_indents {
- uint::max_value
- } else {
- min_indent
- };
-
- if saw_first_line {
- saw_second_line = true;
- }
-
- if line.is_whitespace() {
- min_indent
- } else {
- saw_first_line = true;
- let mut spaces = 0;
- do line.iter().all |char| {
- // Only comparing against space because I wouldn't
- // know what to do with mixed whitespace chars
- if char == ' ' {
- spaces += 1;
- true
- } else {
- false
- }
- };
- num::min(min_indent, spaces)
- }
- };
-
- match lines {
- [head, .. tail] => {
- let mut unindented = ~[ head.trim() ];
- unindented.push_all(do tail.map |&line| {
- if line.is_whitespace() {
- line
- } else {
- assert!(line.len() >= min_indent);
- line.slice_from(min_indent)
- }
- });
- unindented.connect("\n")
- }
- [] => s.to_owned()
- }
-}
-
-#[test]
-fn should_unindent() {
- let s = ~" line1\n line2";
- let r = unindent(s);
- assert_eq!(r, ~"line1\nline2");
-}
-
-#[test]
-fn should_unindent_multiple_paragraphs() {
- let s = ~" line1\n\n line2";
- let r = unindent(s);
- assert_eq!(r, ~"line1\n\nline2");
-}
-
-#[test]
-fn should_leave_multiple_indent_levels() {
- // Line 2 is indented another level beyond the
- // base indentation and should be preserved
- let s = ~" line1\n\n line2";
- let r = unindent(s);
- assert_eq!(r, ~"line1\n\n line2");
-}
-
-#[test]
-fn should_ignore_first_line_indent() {
- // Thi first line of the first paragraph may not be indented as
- // far due to the way the doc string was written:
- //
- // #[doc = "Start way over here
- // and continue here"]
- let s = ~"line1\n line2";
- let r = unindent(s);
- assert_eq!(r, ~"line1\nline2");
-}
-
-#[test]
-fn should_not_ignore_first_line_indent_in_a_single_line_para() {
- let s = ~"line1\n\n line2";
- let r = unindent(s);
- assert_eq!(r, ~"line1\n\n line2");
-}
--- /dev/null
+// Copyright 2012-2013 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.
+
+//! Rust AST Visitor. Extracts useful information and massages it into a form
+//! usable for clean
+
+use syntax::abi::AbiSet;
+use syntax::{ast, ast_map};
+use syntax::codemap::Span;
+
+use doctree::*;
+use std::local_data;
+
+pub struct RustdocVisitor {
+ module: Module,
+ attrs: ~[ast::Attribute],
+}
+
+impl RustdocVisitor {
+ pub fn new() -> RustdocVisitor {
+ RustdocVisitor {
+ module: Module::new(None),
+ attrs: ~[],
+ }
+ }
+}
+
+impl RustdocVisitor {
+ pub fn visit(@mut self, crate: &ast::Crate) {
+ self.attrs = crate.attrs.clone();
+ fn visit_struct_def(item: &ast::item, sd: @ast::struct_def, generics:
+ &ast::Generics) -> Struct {
+ debug!("Visiting struct");
+ let struct_type = struct_type_from_def(sd);
+ Struct {
+ id: item.id,
+ struct_type: struct_type,
+ name: item.ident,
+ vis: item.vis,
+ attrs: item.attrs.clone(),
+ generics: generics.clone(),
+ fields: sd.fields.iter().map(|x| (*x).clone()).to_owned_vec(),
+ where: item.span
+ }
+ }
+
+ fn visit_enum_def(it: &ast::item, def: &ast::enum_def, params: &ast::Generics) -> Enum {
+ debug!("Visiting enum");
+ let mut vars: ~[Variant] = ~[];
+ for x in def.variants.iter() {
+ vars.push(Variant {
+ name: x.node.name,
+ attrs: x.node.attrs.clone(),
+ vis: x.node.vis,
+ id: x.node.id,
+ kind: x.node.kind.clone(),
+ where: x.span,
+ });
+ }
+ Enum {
+ name: it.ident,
+ variants: vars,
+ vis: it.vis,
+ generics: params.clone(),
+ attrs: it.attrs.clone(),
+ id: it.id,
+ where: it.span,
+ }
+ }
+
+ fn visit_fn(item: &ast::item, fd: &ast::fn_decl, _purity: &ast::purity,
+ _abi: &AbiSet, gen: &ast::Generics) -> Function {
+ debug!("Visiting fn");
+ Function {
+ id: item.id,
+ vis: item.vis,
+ attrs: item.attrs.clone(),
+ decl: fd.clone(),
+ name: item.ident,
+ where: item.span,
+ generics: gen.clone(),
+ }
+ }
+
+ fn visit_mod_contents(span: Span, attrs: ~[ast::Attribute], vis:
+ ast::visibility, id: ast::NodeId, m: &ast::_mod) -> Module {
+ let am = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.items;
+ let name = match am.find(&id) {
+ Some(m) => match m {
+ &ast_map::node_item(ref it, _) => Some(it.ident),
+ _ => fail!("mod id mapped to non-item in the ast map")
+ },
+ None => None
+ };
+ let mut om = Module::new(name);
+ om.view_items = m.view_items.clone();
+ om.where = span;
+ om.attrs = attrs;
+ om.vis = vis;
+ om.id = id;
+ for i in m.items.iter() {
+ visit_item(*i, &mut om);
+ }
+ om
+ }
+
+ fn visit_item(item: &ast::item, om: &mut Module) {
+ debug!("Visiting item %?", item);
+ match item.node {
+ ast::item_mod(ref m) => {
+ om.mods.push(visit_mod_contents(item.span, item.attrs.clone(),
+ item.vis, item.id, m));
+ },
+ ast::item_enum(ref ed, ref gen) => om.enums.push(visit_enum_def(item, ed, gen)),
+ ast::item_struct(sd, ref gen) => om.structs.push(visit_struct_def(item, sd, gen)),
+ ast::item_fn(ref fd, ref pur, ref abi, ref gen, _) =>
+ om.fns.push(visit_fn(item, fd, pur, abi, gen)),
+ ast::item_ty(ref ty, ref gen) => {
+ let t = Typedef {
+ ty: ty.clone(),
+ gen: gen.clone(),
+ name: item.ident,
+ id: item.id,
+ attrs: item.attrs.clone(),
+ where: item.span,
+ vis: item.vis,
+ };
+ om.typedefs.push(t);
+ },
+ ast::item_static(ref ty, ref mut_, ref exp) => {
+ let s = Static {
+ type_: ty.clone(),
+ mutability: mut_.clone(),
+ expr: exp.clone(),
+ id: item.id,
+ name: item.ident,
+ attrs: item.attrs.clone(),
+ where: item.span,
+ vis: item.vis,
+ };
+ om.statics.push(s);
+ },
+ ast::item_trait(ref gen, ref tr, ref met) => {
+ let t = Trait {
+ name: item.ident,
+ methods: met.clone(),
+ generics: gen.clone(),
+ parents: tr.clone(),
+ id: item.id,
+ attrs: item.attrs.clone(),
+ where: item.span,
+ vis: item.vis,
+ };
+ om.traits.push(t);
+ },
+ ast::item_impl(ref gen, ref tr, ref ty, ref meths) => {
+ let i = Impl {
+ generics: gen.clone(),
+ trait_: tr.clone(),
+ for_: ty.clone(),
+ methods: meths.clone(),
+ attrs: item.attrs.clone(),
+ id: item.id,
+ where: item.span,
+ vis: item.vis,
+ };
+ om.impls.push(i);
+ },
+ _ => (),
+ }
+ }
+
+ self.module = visit_mod_contents(crate.span, crate.attrs.clone(),
+ ast::public, ast::CRATE_NODE_ID, &crate.module);
+ }
+}
*/
#[link(name = "rusti",
- vers = "0.8-pre",
+ vers = "0.8",
uuid = "7fb5bf52-7d45-4fee-8325-5ad3311149fc",
url = "https://github.com/mozilla/rust/tree/master/src/rusti")];
// rustpkg - a package manager and build system for Rust
#[link(name = "rustpkg",
- vers = "0.8-pre",
+ vers = "0.8",
uuid = "25de5e6e-279e-4a20-845c-4cabae92daaf",
url = "https://github.com/mozilla/rust/tree/master/src/librustpkg")];
use iter::{FilterMap, Chain, Repeat, Zip};
use num;
use option::{None, Option, Some};
-use rand::RngUtil;
+use rand::Rng;
use rand;
use uint;
use util::replace;
#[cfg(test)]
mod bench {
use extra::test::BenchHarness;
- use rand::{XorShiftRng,RngUtil};
+ use rand::{XorShiftRng, Rng};
use float;
use to_str::ToStr;
use os::{remove_file, setenv, unsetenv};
use os;
use path::Path;
- use rand::RngUtil;
+ use rand::Rng;
use rand;
use run;
use str::StrSlice;
fn make_rand_name() -> ~str {
let mut rng = rand::rng();
- let n = ~"TEST" + rng.gen_str(10u);
+ let n = ~"TEST" + rng.gen_ascii_str(10u);
assert!(getenv(n).is_none());
n
}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-Random number generation.
-
-The key functions are `random()` and `RngUtil::gen()`. These are polymorphic
-and so can be used to generate any type that implements `Rand`. Type inference
-means that often a simple call to `rand::random()` or `rng.gen()` will
-suffice, but sometimes an annotation is required, e.g. `rand::random::<float>()`.
-
-See the `distributions` submodule for sampling random numbers from
-distributions like normal and exponential.
-
-# Examples
-
-~~~ {.rust}
-use std::rand;
-use std::rand::RngUtil;
-
-fn main() {
- let mut rng = rand::rng();
- if rng.gen() { // bool
- printfln!("int: %d, uint: %u", rng.gen(), rng.gen())
- }
-}
-~~~
-
-~~~ {.rust}
-use std::rand;
-
-fn main () {
- let tuple_ptr = rand::random::<~(f64, char)>();
- printfln!(tuple_ptr)
-}
-~~~
-*/
-
-use cast;
-use clone::Clone;
-use cmp;
-use container::Container;
-use int;
-use iter::{Iterator, range, range_step};
-use local_data;
-use num;
-use prelude::*;
-use str;
-use sys;
-use u32;
-use uint;
-use vec;
-use libc::size_t;
-
-#[path="rand/distributions.rs"]
-pub mod distributions;
-
-/// A type that can be randomly generated using an Rng
-pub trait Rand {
- /// Generates a random instance of this type using the specified source of
- /// randomness
- fn rand<R: Rng>(rng: &mut R) -> Self;
-}
-
-impl Rand for int {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> int {
- if int::bits == 32 {
- rng.next() as int
- } else {
- rng.gen::<i64>() as int
- }
- }
-}
-
-impl Rand for i8 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> i8 {
- rng.next() as i8
- }
-}
-
-impl Rand for i16 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> i16 {
- rng.next() as i16
- }
-}
-
-impl Rand for i32 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> i32 {
- rng.next() as i32
- }
-}
-
-impl Rand for i64 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> i64 {
- (rng.next() as i64 << 32) | rng.next() as i64
- }
-}
-
-impl Rand for uint {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> uint {
- if uint::bits == 32 {
- rng.next() as uint
- } else {
- rng.gen::<u64>() as uint
- }
- }
-}
-
-impl Rand for u8 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> u8 {
- rng.next() as u8
- }
-}
-
-impl Rand for u16 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> u16 {
- rng.next() as u16
- }
-}
-
-impl Rand for u32 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> u32 {
- rng.next()
- }
-}
-
-impl Rand for u64 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> u64 {
- (rng.next() as u64 << 32) | rng.next() as u64
- }
-}
-
-impl Rand for float {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> float {
- rng.gen::<f64>() as float
- }
-}
-
-impl Rand for f32 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> f32 {
- rng.gen::<f64>() as f32
- }
-}
-
-static SCALE : f64 = (u32::max_value as f64) + 1.0f64;
-impl Rand for f64 {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> f64 {
- let u1 = rng.next() as f64;
- let u2 = rng.next() as f64;
- let u3 = rng.next() as f64;
-
- ((u1 / SCALE + u2) / SCALE + u3) / SCALE
- }
-}
-
-impl Rand for bool {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> bool {
- rng.next() & 1u32 == 1u32
- }
-}
-
-macro_rules! tuple_impl {
- // use variables to indicate the arity of the tuple
- ($($tyvar:ident),* ) => {
- // the trailing commas are for the 1 tuple
- impl<
- $( $tyvar : Rand ),*
- > Rand for ( $( $tyvar ),* , ) {
-
- #[inline]
- fn rand<R: Rng>(_rng: &mut R) -> ( $( $tyvar ),* , ) {
- (
- // use the $tyvar's to get the appropriate number of
- // repeats (they're not actually needed)
- $(
- _rng.gen::<$tyvar>()
- ),*
- ,
- )
- }
- }
- }
-}
-
-impl Rand for () {
- #[inline]
- fn rand<R: Rng>(_: &mut R) -> () { () }
-}
-tuple_impl!{A}
-tuple_impl!{A, B}
-tuple_impl!{A, B, C}
-tuple_impl!{A, B, C, D}
-tuple_impl!{A, B, C, D, E}
-tuple_impl!{A, B, C, D, E, F}
-tuple_impl!{A, B, C, D, E, F, G}
-tuple_impl!{A, B, C, D, E, F, G, H}
-tuple_impl!{A, B, C, D, E, F, G, H, I}
-tuple_impl!{A, B, C, D, E, F, G, H, I, J}
-
-impl<T:Rand> Rand for Option<T> {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> Option<T> {
- if rng.gen() {
- Some(rng.gen())
- } else {
- None
- }
- }
-}
-
-impl<T: Rand> Rand for ~T {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> ~T { ~rng.gen() }
-}
-
-impl<T: Rand + 'static> Rand for @T {
- #[inline]
- fn rand<R: Rng>(rng: &mut R) -> @T { @rng.gen() }
-}
-
-#[abi = "cdecl"]
-pub mod rustrt {
- use libc::size_t;
-
- extern {
- pub fn rand_seed_size() -> size_t;
- pub fn rand_gen_seed(buf: *mut u8, sz: size_t);
- }
-}
-
-/// A random number generator
-pub trait Rng {
- /// Return the next random integer
- fn next(&mut self) -> u32;
-}
-
-/// A value with a particular weight compared to other values
-pub struct Weighted<T> {
- /// The numerical weight of this item
- weight: uint,
- /// The actual item which is being weighted
- item: T,
-}
-
-/// Helper functions attached to the Rng type
-pub trait RngUtil {
- /// Return a random value of a Rand type
- fn gen<T:Rand>(&mut self) -> T;
- /**
- * Return a int randomly chosen from the range [start, end),
- * failing if start >= end
- */
- fn gen_int_range(&mut self, start: int, end: int) -> int;
- /**
- * Return a uint randomly chosen from the range [start, end),
- * failing if start >= end
- */
- fn gen_uint_range(&mut self, start: uint, end: uint) -> uint;
- /**
- * Return a char randomly chosen from chars, failing if chars is empty
- */
- fn gen_char_from(&mut self, chars: &str) -> char;
- /**
- * Return a bool with a 1 in n chance of true
- *
- * # Example
- *
- * ~~~ {.rust}
- *
- * use std::rand;
- * use std::rand::RngUtil;
- *
- * fn main() {
- * let mut rng = rand::rng();
- * printfln!("%b", rng.gen_weighted_bool(3));
- * }
- * ~~~
- */
- fn gen_weighted_bool(&mut self, n: uint) -> bool;
- /**
- * Return a random string of the specified length composed of A-Z,a-z,0-9
- *
- * # Example
- *
- * ~~~ {.rust}
- *
- * use std::rand;
- * use std::rand::RngUtil;
- *
- * fn main() {
- * let mut rng = rand::rng();
- * println(rng.gen_str(8));
- * }
- * ~~~
- */
- fn gen_str(&mut self, len: uint) -> ~str;
- /**
- * Return a random byte string of the specified length
- *
- * # Example
- *
- * ~~~ {.rust}
- *
- * use std::rand;
- * use std::rand::RngUtil;
- *
- * fn main() {
- * let mut rng = rand::rng();
- * printfln!(rng.gen_bytes(8));
- * }
- * ~~~
- */
- fn gen_bytes(&mut self, len: uint) -> ~[u8];
- /**
- * Choose an item randomly, failing if values is empty
- *
- * # Example
- *
- * ~~~ {.rust}
- *
- * use std::rand;
- * use std::rand::RngUtil;
- *
- * fn main() {
- * let mut rng = rand::rng();
- * printfln!("%d", rng.choose([1,2,4,8,16,32]));
- * }
- * ~~~
- */
- fn choose<T:Clone>(&mut self, values: &[T]) -> T;
- /// Choose Some(item) randomly, returning None if values is empty
- fn choose_option<T:Clone>(&mut self, values: &[T]) -> Option<T>;
- /**
- * Choose an item respecting the relative weights, failing if the sum of
- * the weights is 0
- *
- * # Example
- *
- * ~~~ {.rust}
- *
- * use std::rand;
- * use std::rand::RngUtil;
- *
- * fn main() {
- * let mut rng = rand::rng();
- * let x = [rand::Weighted {weight: 4, item: 'a'},
- * rand::Weighted {weight: 2, item: 'b'},
- * rand::Weighted {weight: 2, item: 'c'}];
- * printfln!("%c", rng.choose_weighted(x));
- * }
- * ~~~
- */
- fn choose_weighted<T:Clone>(&mut self, v : &[Weighted<T>]) -> T;
- /**
- * Choose Some(item) respecting the relative weights, returning none if
- * the sum of the weights is 0
- *
- * # Example
- *
- * ~~~ {.rust}
- *
- * use std::rand;
- * use std::rand::RngUtil;
- *
- * fn main() {
- * let mut rng = rand::rng();
- * let x = [rand::Weighted {weight: 4, item: 'a'},
- * rand::Weighted {weight: 2, item: 'b'},
- * rand::Weighted {weight: 2, item: 'c'}];
- * printfln!(rng.choose_weighted_option(x));
- * }
- * ~~~
- */
- fn choose_weighted_option<T:Clone>(&mut self, v: &[Weighted<T>])
- -> Option<T>;
- /**
- * Return a vec containing copies of the items, in order, where
- * the weight of the item determines how many copies there are
- *
- * # Example
- *
- * ~~~ {.rust}
- *
- * use std::rand;
- * use std::rand::RngUtil;
- *
- * fn main() {
- * let mut rng = rand::rng();
- * let x = [rand::Weighted {weight: 4, item: 'a'},
- * rand::Weighted {weight: 2, item: 'b'},
- * rand::Weighted {weight: 2, item: 'c'}];
- * printfln!(rng.weighted_vec(x));
- * }
- * ~~~
- */
- fn weighted_vec<T:Clone>(&mut self, v: &[Weighted<T>]) -> ~[T];
- /**
- * Shuffle a vec
- *
- * # Example
- *
- * ~~~ {.rust}
- *
- * use std::rand;
- * use std::rand::RngUtil;
- *
- * fn main() {
- * let mut rng = rand::rng();
- * printfln!(rng.shuffle([1,2,3]));
- * }
- * ~~~
- */
- fn shuffle<T:Clone>(&mut self, values: &[T]) -> ~[T];
- /**
- * Shuffle a mutable vec in place
- *
- * # Example
- *
- * ~~~ {.rust}
- *
- * use std::rand;
- * use std::rand::RngUtil;
- *
- * fn main() {
- * let mut rng = rand::rng();
- * let mut y = [1,2,3];
- * rng.shuffle_mut(y);
- * printfln!(y);
- * rng.shuffle_mut(y);
- * printfln!(y);
- * }
- * ~~~
- */
- fn shuffle_mut<T>(&mut self, values: &mut [T]);
-
- /**
- * Sample up to `n` values from an iterator.
- *
- * # Example
- *
- * ~~~ {.rust}
- *
- * use std::rand;
- * use std::rand::RngUtil;
- *
- * fn main() {
- * let mut rng = rand::rng();
- * let vals = range(1, 100).to_owned_vec();
- * let sample = rng.sample(vals.iter(), 5);
- * printfln!(sample);
- * }
- * ~~~
- */
- fn sample<A, T: Iterator<A>>(&mut self, iter: T, n: uint) -> ~[A];
-}
-
-/// Extension methods for random number generators
-impl<R: Rng> RngUtil for R {
- /// Return a random value for a Rand type
- #[inline]
- fn gen<T: Rand>(&mut self) -> T {
- Rand::rand(self)
- }
-
- /**
- * Return an int randomly chosen from the range [start, end),
- * failing if start >= end
- */
- fn gen_int_range(&mut self, start: int, end: int) -> int {
- assert!(start < end);
- start + num::abs(self.gen::<int>() % (end - start))
- }
-
- /**
- * Return a uint randomly chosen from the range [start, end),
- * failing if start >= end
- */
- fn gen_uint_range(&mut self, start: uint, end: uint) -> uint {
- assert!(start < end);
- start + (self.gen::<uint>() % (end - start))
- }
-
- /**
- * Return a char randomly chosen from chars, failing if chars is empty
- */
- fn gen_char_from(&mut self, chars: &str) -> char {
- assert!(!chars.is_empty());
- let mut cs = ~[];
- for c in chars.iter() { cs.push(c) }
- self.choose(cs)
- }
-
- /// Return a bool with a 1-in-n chance of true
- fn gen_weighted_bool(&mut self, n: uint) -> bool {
- if n == 0u {
- true
- } else {
- self.gen_uint_range(1u, n + 1u) == 1u
- }
- }
-
- /**
- * Return a random string of the specified length composed of A-Z,a-z,0-9
- */
- fn gen_str(&mut self, len: uint) -> ~str {
- let charset = ~"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
- abcdefghijklmnopqrstuvwxyz\
- 0123456789";
- let mut s = ~"";
- let mut i = 0u;
- while (i < len) {
- s = s + str::from_char(self.gen_char_from(charset));
- i += 1u;
- }
- s
- }
-
- /// Return a random byte string of the specified length
- fn gen_bytes(&mut self, len: uint) -> ~[u8] {
- do vec::from_fn(len) |_i| {
- self.gen()
- }
- }
-
- /// Choose an item randomly, failing if values is empty
- fn choose<T:Clone>(&mut self, values: &[T]) -> T {
- self.choose_option(values).unwrap()
- }
-
- /// Choose Some(item) randomly, returning None if values is empty
- fn choose_option<T:Clone>(&mut self, values: &[T]) -> Option<T> {
- if values.is_empty() {
- None
- } else {
- Some(values[self.gen_uint_range(0u, values.len())].clone())
- }
- }
- /**
- * Choose an item respecting the relative weights, failing if the sum of
- * the weights is 0
- */
- fn choose_weighted<T:Clone>(&mut self, v: &[Weighted<T>]) -> T {
- self.choose_weighted_option(v).unwrap()
- }
-
- /**
- * Choose Some(item) respecting the relative weights, returning none if
- * the sum of the weights is 0
- */
- fn choose_weighted_option<T:Clone>(&mut self, v: &[Weighted<T>])
- -> Option<T> {
- let mut total = 0u;
- for item in v.iter() {
- total += item.weight;
- }
- if total == 0u {
- return None;
- }
- let chosen = self.gen_uint_range(0u, total);
- let mut so_far = 0u;
- for item in v.iter() {
- so_far += item.weight;
- if so_far > chosen {
- return Some(item.item.clone());
- }
- }
- unreachable!();
- }
-
- /**
- * Return a vec containing copies of the items, in order, where
- * the weight of the item determines how many copies there are
- */
- fn weighted_vec<T:Clone>(&mut self, v: &[Weighted<T>]) -> ~[T] {
- let mut r = ~[];
- for item in v.iter() {
- for _ in range(0u, item.weight) {
- r.push(item.item.clone());
- }
- }
- r
- }
-
- /// Shuffle a vec
- fn shuffle<T:Clone>(&mut self, values: &[T]) -> ~[T] {
- let mut m = values.to_owned();
- self.shuffle_mut(m);
- m
- }
-
- /// Shuffle a mutable vec in place
- fn shuffle_mut<T>(&mut self, values: &mut [T]) {
- let mut i = values.len();
- while i >= 2u {
- // invariant: elements with index >= i have been locked in place.
- i -= 1u;
- // lock element i in place.
- values.swap(i, self.gen_uint_range(0u, i + 1u));
- }
- }
-
- /// Randomly sample up to `n` elements from an iterator
- fn sample<A, T: Iterator<A>>(&mut self, iter: T, n: uint) -> ~[A] {
- let mut reservoir : ~[A] = vec::with_capacity(n);
- for (i, elem) in iter.enumerate() {
- if i < n {
- reservoir.push(elem);
- loop
- }
-
- let k = self.gen_uint_range(0, i + 1);
- if k < reservoir.len() {
- reservoir[k] = elem
- }
- }
- reservoir
- }
-}
-
-/// Create a random number generator with a default algorithm and seed.
-///
-/// It returns the cryptographically-safest `Rng` algorithm currently
-/// available in Rust. If you require a specifically seeded `Rng` for
-/// consistency over time you should pick one algorithm and create the
-/// `Rng` yourself.
-pub fn rng() -> IsaacRng {
- IsaacRng::new()
-}
-
-/// Create a weak random number generator with a default algorithm and seed.
-///
-/// It returns the fastest `Rng` algorithm currently available in Rust without
-/// consideration for cryptography or security. If you require a specifically
-/// seeded `Rng` for consistency over time you should pick one algorithm and
-/// create the `Rng` yourself.
-pub fn weak_rng() -> XorShiftRng {
- XorShiftRng::new()
-}
-
-static RAND_SIZE_LEN: u32 = 8;
-static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
-
-/// A random number generator that uses the [ISAAC
-/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
-///
-/// The ISAAC algorithm is suitable for cryptographic purposes.
-pub struct IsaacRng {
- priv cnt: u32,
- priv rsl: [u32, .. RAND_SIZE],
- priv mem: [u32, .. RAND_SIZE],
- priv a: u32,
- priv b: u32,
- priv c: u32
-}
-
-impl IsaacRng {
- /// Create an ISAAC random number generator with a random seed.
- pub fn new() -> IsaacRng {
- IsaacRng::new_seeded(seed())
- }
-
- /// Create an ISAAC random number generator with a seed. This can be any
- /// length, although the maximum number of bytes used is 1024 and any more
- /// will be silently ignored. A generator constructed with a given seed
- /// will generate the same sequence of values as all other generators
- /// constructed with the same seed.
- pub fn new_seeded(seed: &[u8]) -> IsaacRng {
- let mut rng = IsaacRng {
- cnt: 0,
- rsl: [0, .. RAND_SIZE],
- mem: [0, .. RAND_SIZE],
- a: 0, b: 0, c: 0
- };
-
- let array_size = sys::size_of_val(&rng.rsl);
- let copy_length = cmp::min(array_size, seed.len());
-
- // manually create a &mut [u8] slice of randrsl to copy into.
- let dest = unsafe { cast::transmute((&mut rng.rsl, array_size)) };
- vec::bytes::copy_memory(dest, seed, copy_length);
- rng.init(true);
- rng
- }
-
- /// Create an ISAAC random number generator using the default
- /// fixed seed.
- pub fn new_unseeded() -> IsaacRng {
- let mut rng = IsaacRng {
- cnt: 0,
- rsl: [0, .. RAND_SIZE],
- mem: [0, .. RAND_SIZE],
- a: 0, b: 0, c: 0
- };
- rng.init(false);
- rng
- }
-
- /// Initialises `self`. If `use_rsl` is true, then use the current value
- /// of `rsl` as a seed, otherwise construct one algorithmically (not
- /// randomly).
- fn init(&mut self, use_rsl: bool) {
- let mut a = 0x9e3779b9;
- let mut b = a;
- let mut c = a;
- let mut d = a;
- let mut e = a;
- let mut f = a;
- let mut g = a;
- let mut h = a;
-
- macro_rules! mix(
- () => {{
- a^=b<<11; d+=a; b+=c;
- b^=c>>2; e+=b; c+=d;
- c^=d<<8; f+=c; d+=e;
- d^=e>>16; g+=d; e+=f;
- e^=f<<10; h+=e; f+=g;
- f^=g>>4; a+=f; g+=h;
- g^=h<<8; b+=g; h+=a;
- h^=a>>9; c+=h; a+=b;
- }}
- );
-
- do 4.times { mix!(); }
-
- if use_rsl {
- macro_rules! memloop (
- ($arr:expr) => {{
- for i in range_step(0u32, RAND_SIZE, 8) {
- a+=$arr[i ]; b+=$arr[i+1];
- c+=$arr[i+2]; d+=$arr[i+3];
- e+=$arr[i+4]; f+=$arr[i+5];
- g+=$arr[i+6]; h+=$arr[i+7];
- mix!();
- self.mem[i ]=a; self.mem[i+1]=b;
- self.mem[i+2]=c; self.mem[i+3]=d;
- self.mem[i+4]=e; self.mem[i+5]=f;
- self.mem[i+6]=g; self.mem[i+7]=h;
- }
- }}
- );
-
- memloop!(self.rsl);
- memloop!(self.mem);
- } else {
- for i in range_step(0u32, RAND_SIZE, 8) {
- mix!();
- self.mem[i ]=a; self.mem[i+1]=b;
- self.mem[i+2]=c; self.mem[i+3]=d;
- self.mem[i+4]=e; self.mem[i+5]=f;
- self.mem[i+6]=g; self.mem[i+7]=h;
- }
- }
-
- self.isaac();
- }
-
- /// Refills the output buffer (`self.rsl`)
- #[inline]
- fn isaac(&mut self) {
- self.c += 1;
- // abbreviations
- let mut a = self.a;
- let mut b = self.b + self.c;
-
- static MIDPOINT: uint = RAND_SIZE as uint / 2;
-
- macro_rules! ind (($x:expr) => {
- self.mem[($x >> 2) & (RAND_SIZE - 1)]
- });
- macro_rules! rngstep(
- ($j:expr, $shift:expr) => {{
- let base = $j;
- let mix = if $shift < 0 {
- a >> -$shift as uint
- } else {
- a << $shift as uint
- };
-
- let x = self.mem[base + mr_offset];
- a = (a ^ mix) + self.mem[base + m2_offset];
- let y = ind!(x) + a + b;
- self.mem[base + mr_offset] = y;
-
- b = ind!(y >> RAND_SIZE_LEN) + x;
- self.rsl[base + mr_offset] = b;
- }}
- );
-
- let r = [(0, MIDPOINT), (MIDPOINT, 0)];
- for &(mr_offset, m2_offset) in r.iter() {
- for i in range_step(0u, MIDPOINT, 4) {
- rngstep!(i + 0, 13);
- rngstep!(i + 1, -6);
- rngstep!(i + 2, 2);
- rngstep!(i + 3, -16);
- }
- }
-
- self.a = a;
- self.b = b;
- self.cnt = RAND_SIZE;
- }
-}
-
-impl Rng for IsaacRng {
- #[inline]
- fn next(&mut self) -> u32 {
- if self.cnt == 0 {
- // make some more numbers
- self.isaac();
- }
- self.cnt -= 1;
- self.rsl[self.cnt]
- }
-}
-
-/// An [Xorshift random number
-/// generator](http://en.wikipedia.org/wiki/Xorshift).
-///
-/// The Xorshift algorithm is not suitable for cryptographic purposes
-/// but is very fast. If you do not know for sure that it fits your
-/// requirements, use a more secure one such as `IsaacRng`.
-pub struct XorShiftRng {
- priv x: u32,
- priv y: u32,
- priv z: u32,
- priv w: u32,
-}
-
-impl Rng for XorShiftRng {
- #[inline]
- fn next(&mut self) -> u32 {
- let x = self.x;
- let t = x ^ (x << 11);
- self.x = self.y;
- self.y = self.z;
- self.z = self.w;
- let w = self.w;
- self.w = w ^ (w >> 19) ^ (t ^ (t >> 8));
- self.w
- }
-}
-
-impl XorShiftRng {
- /// Create an xor shift random number generator with a random seed.
- pub fn new() -> XorShiftRng {
- #[fixed_stack_segment]; #[inline(never)];
-
- // generate seeds the same way as seed(), except we have a spceific size
- let mut s = [0u8, ..16];
- loop {
- do s.as_mut_buf |p, sz| {
- unsafe {
- rustrt::rand_gen_seed(p, sz as size_t);
- }
- }
- if !s.iter().all(|x| *x == 0) {
- break;
- }
- }
- let s: &[u32, ..4] = unsafe { cast::transmute(&s) };
- XorShiftRng::new_seeded(s[0], s[1], s[2], s[3])
- }
-
- /**
- * Create a random number generator using the specified seed. A generator
- * constructed with a given seed will generate the same sequence of values
- * as all other generators constructed with the same seed.
- */
- pub fn new_seeded(x: u32, y: u32, z: u32, w: u32) -> XorShiftRng {
- XorShiftRng {
- x: x,
- y: y,
- z: z,
- w: w,
- }
- }
-}
-
-/// Create a new random seed.
-pub fn seed() -> ~[u8] {
- #[fixed_stack_segment]; #[inline(never)];
-
- unsafe {
- let n = rustrt::rand_seed_size() as uint;
- let mut s = vec::from_elem(n, 0_u8);
- do s.as_mut_buf |p, sz| {
- rustrt::rand_gen_seed(p, sz as size_t)
- }
- s
- }
-}
-
-// used to make space in TLS for a random number generator
-local_data_key!(tls_rng_state: @@mut IsaacRng)
-
-/**
- * Gives back a lazily initialized task-local random number generator,
- * seeded by the system. Intended to be used in method chaining style, ie
- * `task_rng().gen::<int>()`.
- */
-#[inline]
-pub fn task_rng() -> @mut IsaacRng {
- let r = local_data::get(tls_rng_state, |k| k.map(|&k| *k));
- match r {
- None => {
- let rng = @@mut IsaacRng::new_seeded(seed());
- local_data::set(tls_rng_state, rng);
- *rng
- }
- Some(rng) => *rng
- }
-}
-
-// Allow direct chaining with `task_rng`
-impl<R: Rng> Rng for @mut R {
- #[inline]
- fn next(&mut self) -> u32 {
- (**self).next()
- }
-}
-
-/**
- * Returns a random value of a Rand type, using the task's random number
- * generator.
- */
-#[inline]
-pub fn random<T: Rand>() -> T {
- task_rng().gen()
-}
-
-#[cfg(test)]
-mod test {
- use iter::{Iterator, range};
- use option::{Option, Some};
- use super::*;
-
- #[test]
- fn test_rng_seeded() {
- let seed = seed();
- let mut ra = IsaacRng::new_seeded(seed);
- let mut rb = IsaacRng::new_seeded(seed);
- assert_eq!(ra.gen_str(100u), rb.gen_str(100u));
- }
-
- #[test]
- fn test_rng_seeded_custom_seed() {
- // much shorter than generated seeds which are 1024 bytes
- let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
- let mut ra = IsaacRng::new_seeded(seed);
- let mut rb = IsaacRng::new_seeded(seed);
- assert_eq!(ra.gen_str(100u), rb.gen_str(100u));
- }
-
- #[test]
- fn test_rng_seeded_custom_seed2() {
- let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
- let mut ra = IsaacRng::new_seeded(seed);
- // Regression test that isaac is actually using the above vector
- let r = ra.next();
- error!("%?", r);
- assert!(r == 890007737u32 // on x86_64
- || r == 2935188040u32); // on x86
- }
-
- #[test]
- fn test_gen_int_range() {
- let mut r = rng();
- let a = r.gen_int_range(-3, 42);
- assert!(a >= -3 && a < 42);
- assert_eq!(r.gen_int_range(0, 1), 0);
- assert_eq!(r.gen_int_range(-12, -11), -12);
- }
-
- #[test]
- #[should_fail]
- fn test_gen_int_from_fail() {
- let mut r = rng();
- r.gen_int_range(5, -2);
- }
-
- #[test]
- fn test_gen_uint_range() {
- let mut r = rng();
- let a = r.gen_uint_range(3u, 42u);
- assert!(a >= 3u && a < 42u);
- assert_eq!(r.gen_uint_range(0u, 1u), 0u);
- assert_eq!(r.gen_uint_range(12u, 13u), 12u);
- }
-
- #[test]
- #[should_fail]
- fn test_gen_uint_range_fail() {
- let mut r = rng();
- r.gen_uint_range(5u, 2u);
- }
-
- #[test]
- fn test_gen_float() {
- let mut r = rng();
- let a = r.gen::<float>();
- let b = r.gen::<float>();
- debug!((a, b));
- }
-
- #[test]
- fn test_gen_weighted_bool() {
- let mut r = rng();
- assert_eq!(r.gen_weighted_bool(0u), true);
- assert_eq!(r.gen_weighted_bool(1u), true);
- }
-
- #[test]
- fn test_gen_str() {
- let mut r = rng();
- debug!(r.gen_str(10u));
- debug!(r.gen_str(10u));
- debug!(r.gen_str(10u));
- assert_eq!(r.gen_str(0u).len(), 0u);
- assert_eq!(r.gen_str(10u).len(), 10u);
- assert_eq!(r.gen_str(16u).len(), 16u);
- }
-
- #[test]
- fn test_gen_bytes() {
- let mut r = rng();
- assert_eq!(r.gen_bytes(0u).len(), 0u);
- assert_eq!(r.gen_bytes(10u).len(), 10u);
- assert_eq!(r.gen_bytes(16u).len(), 16u);
- }
-
- #[test]
- fn test_choose() {
- let mut r = rng();
- assert_eq!(r.choose([1, 1, 1]), 1);
- }
-
- #[test]
- fn test_choose_option() {
- let mut r = rng();
- let x: Option<int> = r.choose_option([]);
- assert!(x.is_none());
- assert_eq!(r.choose_option([1, 1, 1]), Some(1));
- }
-
- #[test]
- fn test_choose_weighted() {
- let mut r = rng();
- assert!(r.choose_weighted([
- Weighted { weight: 1u, item: 42 },
- ]) == 42);
- assert!(r.choose_weighted([
- Weighted { weight: 0u, item: 42 },
- Weighted { weight: 1u, item: 43 },
- ]) == 43);
- }
-
- #[test]
- fn test_choose_weighted_option() {
- let mut r = rng();
- assert!(r.choose_weighted_option([
- Weighted { weight: 1u, item: 42 },
- ]) == Some(42));
- assert!(r.choose_weighted_option([
- Weighted { weight: 0u, item: 42 },
- Weighted { weight: 1u, item: 43 },
- ]) == Some(43));
- let v: Option<int> = r.choose_weighted_option([]);
- assert!(v.is_none());
- }
-
- #[test]
- fn test_weighted_vec() {
- let mut r = rng();
- let empty: ~[int] = ~[];
- assert_eq!(r.weighted_vec([]), empty);
- assert!(r.weighted_vec([
- Weighted { weight: 0u, item: 3u },
- Weighted { weight: 1u, item: 2u },
- Weighted { weight: 2u, item: 1u },
- ]) == ~[2u, 1u, 1u]);
- }
-
- #[test]
- fn test_shuffle() {
- let mut r = rng();
- let empty: ~[int] = ~[];
- assert_eq!(r.shuffle([]), empty);
- assert_eq!(r.shuffle([1, 1, 1]), ~[1, 1, 1]);
- }
-
- #[test]
- fn test_task_rng() {
- let mut r = task_rng();
- r.gen::<int>();
- assert_eq!(r.shuffle([1, 1, 1]), ~[1, 1, 1]);
- assert_eq!(r.gen_uint_range(0u, 1u), 0u);
- }
-
- #[test]
- fn test_random() {
- // not sure how to test this aside from just getting some values
- let _n : uint = random();
- let _f : f32 = random();
- let _o : Option<Option<i8>> = random();
- let _many : ((),
- (~uint, @int, ~Option<~(@u32, ~(@bool,))>),
- (u8, i8, u16, i16, u32, i32, u64, i64),
- (f32, (f64, (float,)))) = random();
- }
-
- #[test]
- fn compare_isaac_implementation() {
- #[fixed_stack_segment]; #[inline(never)];
-
- // This is to verify that the implementation of the ISAAC rng is
- // correct (i.e. matches the output of the upstream implementation,
- // which is in the runtime)
- use libc::size_t;
-
- #[abi = "cdecl"]
- mod rustrt {
- use libc::size_t;
-
- #[allow(non_camel_case_types)] // runtime type
- pub enum rust_rng {}
-
- extern {
- pub fn rand_new_seeded(buf: *u8, sz: size_t) -> *rust_rng;
- pub fn rand_next(rng: *rust_rng) -> u32;
- pub fn rand_free(rng: *rust_rng);
- }
- }
-
- // run against several seeds
- do 10.times {
- unsafe {
- let seed = super::seed();
- let rt_rng = do seed.as_imm_buf |p, sz| {
- rustrt::rand_new_seeded(p, sz as size_t)
- };
- let mut rng = IsaacRng::new_seeded(seed);
-
- do 10000.times {
- assert_eq!(rng.next(), rustrt::rand_next(rt_rng));
- }
- rustrt::rand_free(rt_rng);
- }
- }
- }
-
- #[test]
- fn test_sample() {
- let MIN_VAL = 1;
- let MAX_VAL = 100;
-
- let mut r = rng();
- let vals = range(MIN_VAL, MAX_VAL).to_owned_vec();
- let small_sample = r.sample(vals.iter(), 5);
- let large_sample = r.sample(vals.iter(), vals.len() + 5);
-
- assert_eq!(small_sample.len(), 5);
- assert_eq!(large_sample.len(), vals.len());
-
- assert!(small_sample.iter().all(|e| {
- **e >= MIN_VAL && **e <= MAX_VAL
- }));
- }
-}
-
-#[cfg(test)]
-mod bench {
- use extra::test::BenchHarness;
- use rand::*;
- use sys::size_of;
-
- #[bench]
- fn rand_xorshift(bh: &mut BenchHarness) {
- let mut rng = XorShiftRng::new();
- do bh.iter {
- rng.gen::<uint>();
- }
- bh.bytes = size_of::<uint>() as u64;
- }
-
- #[bench]
- fn rand_isaac(bh: &mut BenchHarness) {
- let mut rng = IsaacRng::new();
- do bh.iter {
- rng.gen::<uint>();
- }
- bh.bytes = size_of::<uint>() as u64;
- }
-
- #[bench]
- fn rand_shuffle_100(bh: &mut BenchHarness) {
- let mut rng = XorShiftRng::new();
- let x : &mut[uint] = [1,..100];
- do bh.iter {
- rng.shuffle_mut(x);
- }
- }
-}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+Random number generation.
+
+The key functions are `random()` and `Rng::gen()`. These are polymorphic
+and so can be used to generate any type that implements `Rand`. Type inference
+means that often a simple call to `rand::random()` or `rng.gen()` will
+suffice, but sometimes an annotation is required, e.g. `rand::random::<float>()`.
+
+See the `distributions` submodule for sampling random numbers from
+distributions like normal and exponential.
+
+# Examples
+
+~~~ {.rust}
+use std::rand;
+use std::rand::Rng;
+
+fn main() {
+ let mut rng = rand::rng();
+ if rng.gen() { // bool
+ printfln!("int: %d, uint: %u", rng.gen(), rng.gen())
+ }
+}
+~~~
+
+~~~ {.rust}
+use std::rand;
+
+fn main () {
+ let tuple_ptr = rand::random::<~(f64, char)>();
+ printfln!(tuple_ptr)
+}
+~~~
+*/
+
+use cast;
+use cmp;
+use container::Container;
+use int;
+use iter::{Iterator, range, range_step};
+use local_data;
+use prelude::*;
+use str;
+use sys;
+use u32;
+use u64;
+use uint;
+use vec;
+use libc::size_t;
+
+pub mod distributions;
+
+/// A type that can be randomly generated using an Rng
+pub trait Rand {
+ /// Generates a random instance of this type using the specified source of
+ /// randomness
+ fn rand<R: Rng>(rng: &mut R) -> Self;
+}
+
+impl Rand for int {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> int {
+ if int::bits == 32 {
+ rng.next() as int
+ } else {
+ rng.gen::<i64>() as int
+ }
+ }
+}
+
+impl Rand for i8 {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> i8 {
+ rng.next() as i8
+ }
+}
+
+impl Rand for i16 {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> i16 {
+ rng.next() as i16
+ }
+}
+
+impl Rand for i32 {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> i32 {
+ rng.next() as i32
+ }
+}
+
+impl Rand for i64 {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> i64 {
+ (rng.next() as i64 << 32) | rng.next() as i64
+ }
+}
+
+impl Rand for uint {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> uint {
+ if uint::bits == 32 {
+ rng.next() as uint
+ } else {
+ rng.gen::<u64>() as uint
+ }
+ }
+}
+
+impl Rand for u8 {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> u8 {
+ rng.next() as u8
+ }
+}
+
+impl Rand for u16 {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> u16 {
+ rng.next() as u16
+ }
+}
+
+impl Rand for u32 {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> u32 {
+ rng.next()
+ }
+}
+
+impl Rand for u64 {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> u64 {
+ (rng.next() as u64 << 32) | rng.next() as u64
+ }
+}
+
+impl Rand for float {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> float {
+ rng.gen::<f64>() as float
+ }
+}
+
+impl Rand for f32 {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> f32 {
+ rng.gen::<f64>() as f32
+ }
+}
+
+static SCALE : f64 = (u32::max_value as f64) + 1.0f64;
+impl Rand for f64 {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> f64 {
+ let u1 = rng.next() as f64;
+ let u2 = rng.next() as f64;
+ let u3 = rng.next() as f64;
+
+ ((u1 / SCALE + u2) / SCALE + u3) / SCALE
+ }
+}
+
+impl Rand for bool {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> bool {
+ rng.next() & 1u32 == 1u32
+ }
+}
+
+macro_rules! tuple_impl {
+ // use variables to indicate the arity of the tuple
+ ($($tyvar:ident),* ) => {
+ // the trailing commas are for the 1 tuple
+ impl<
+ $( $tyvar : Rand ),*
+ > Rand for ( $( $tyvar ),* , ) {
+
+ #[inline]
+ fn rand<R: Rng>(_rng: &mut R) -> ( $( $tyvar ),* , ) {
+ (
+ // use the $tyvar's to get the appropriate number of
+ // repeats (they're not actually needed)
+ $(
+ _rng.gen::<$tyvar>()
+ ),*
+ ,
+ )
+ }
+ }
+ }
+}
+
+impl Rand for () {
+ #[inline]
+ fn rand<R: Rng>(_: &mut R) -> () { () }
+}
+tuple_impl!{A}
+tuple_impl!{A, B}
+tuple_impl!{A, B, C}
+tuple_impl!{A, B, C, D}
+tuple_impl!{A, B, C, D, E}
+tuple_impl!{A, B, C, D, E, F}
+tuple_impl!{A, B, C, D, E, F, G}
+tuple_impl!{A, B, C, D, E, F, G, H}
+tuple_impl!{A, B, C, D, E, F, G, H, I}
+tuple_impl!{A, B, C, D, E, F, G, H, I, J}
+
+impl<T:Rand> Rand for Option<T> {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> Option<T> {
+ if rng.gen() {
+ Some(rng.gen())
+ } else {
+ None
+ }
+ }
+}
+
+impl<T: Rand> Rand for ~T {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> ~T { ~rng.gen() }
+}
+
+impl<T: Rand + 'static> Rand for @T {
+ #[inline]
+ fn rand<R: Rng>(rng: &mut R) -> @T { @rng.gen() }
+}
+
+#[abi = "cdecl"]
+pub mod rustrt {
+ use libc::size_t;
+
+ extern {
+ pub fn rand_gen_seed(buf: *mut u8, sz: size_t);
+ }
+}
+
+/// A value with a particular weight compared to other values
+pub struct Weighted<T> {
+ /// The numerical weight of this item
+ weight: uint,
+ /// The actual item which is being weighted
+ item: T,
+}
+
+/// A random number generator
+pub trait Rng {
+ /// Return the next random integer
+ fn next(&mut self) -> u32;
+
+
+ /// Return a random value of a Rand type.
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ ///
+ /// fn main() {
+ /// let rng = rand::task_rng();
+ /// let x: uint = rng.gen();
+ /// printfln!(x);
+ /// printfln!(rng.gen::<(float, bool)>());
+ /// }
+ /// ~~~
+ #[inline(always)]
+ fn gen<T: Rand>(&mut self) -> T {
+ Rand::rand(self)
+ }
+
+ /// Return a random vector of the specified length.
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ ///
+ /// fn main() {
+ /// let rng = rand::task_rng();
+ /// let x: ~[uint] = rng.gen_vec(10);
+ /// printfln!(x);
+ /// printfln!(rng.gen_vec::<(float, bool)>(5));
+ /// }
+ /// ~~~
+ fn gen_vec<T: Rand>(&mut self, len: uint) -> ~[T] {
+ vec::from_fn(len, |_| self.gen())
+ }
+
+ /// Generate a random primitive integer in the range [`low`,
+ /// `high`). Fails if `low >= high`.
+ ///
+ /// This gives a uniform distribution (assuming this RNG is itself
+ /// uniform), even for edge cases like `gen_integer_range(0u8,
+ /// 170)`, which a naive modulo operation would return numbers
+ /// less than 85 with double the probability to those greater than
+ /// 85.
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ ///
+ /// fn main() {
+ /// let rng = rand::task_rng();
+ /// let n: uint = rng.gen_integer_range(0u, 10);
+ /// printfln!(n);
+ /// let m: i16 = rng.gen_integer_range(-40, 400);
+ /// printfln!(m);
+ /// }
+ /// ~~~
+ fn gen_integer_range<T: Rand + Int>(&mut self, low: T, high: T) -> T {
+ assert!(low < high, "RNG.gen_integer_range called with low >= high");
+ let range = (high - low).to_u64();
+ let accept_zone = u64::max_value - u64::max_value % range;
+ loop {
+ let rand = self.gen::<u64>();
+ if rand < accept_zone {
+ return low + NumCast::from(rand % range);
+ }
+ }
+ }
+
+ /// Return a bool with a 1 in n chance of true
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ /// use std::rand::Rng;
+ ///
+ /// fn main() {
+ /// let mut rng = rand::rng();
+ /// printfln!("%b", rng.gen_weighted_bool(3));
+ /// }
+ /// ~~~
+ fn gen_weighted_bool(&mut self, n: uint) -> bool {
+ n == 0 || self.gen_integer_range(0, n) == 0
+ }
+
+ /// Return a random string of the specified length composed of
+ /// A-Z,a-z,0-9.
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ ///
+ /// fn main() {
+ /// println(rand::task_rng().gen_ascii_str(10));
+ /// }
+ /// ~~~
+ fn gen_ascii_str(&mut self, len: uint) -> ~str {
+ static GEN_ASCII_STR_CHARSET: &'static [u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+ abcdefghijklmnopqrstuvwxyz\
+ 0123456789");
+ let mut s = str::with_capacity(len);
+ for _ in range(0, len) {
+ s.push_char(self.choose(GEN_ASCII_STR_CHARSET) as char)
+ }
+ s
+ }
+
+ /// Choose an item randomly, failing if `values` is empty.
+ fn choose<T: Clone>(&mut self, values: &[T]) -> T {
+ self.choose_option(values).expect("Rng.choose: `values` is empty").clone()
+ }
+
+ /// Choose `Some(&item)` randomly, returning `None` if values is
+ /// empty.
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ ///
+ /// fn main() {
+ /// printfln!(rand::task_rng().choose_option([1,2,4,8,16,32]));
+ /// printfln!(rand::task_rng().choose_option([]));
+ /// }
+ /// ~~~
+ fn choose_option<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> {
+ if values.is_empty() {
+ None
+ } else {
+ Some(&values[self.gen_integer_range(0u, values.len())])
+ }
+ }
+
+ /// Choose an item respecting the relative weights, failing if the sum of
+ /// the weights is 0
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ /// use std::rand::Rng;
+ ///
+ /// fn main() {
+ /// let mut rng = rand::rng();
+ /// let x = [rand::Weighted {weight: 4, item: 'a'},
+ /// rand::Weighted {weight: 2, item: 'b'},
+ /// rand::Weighted {weight: 2, item: 'c'}];
+ /// printfln!("%c", rng.choose_weighted(x));
+ /// }
+ /// ~~~
+ fn choose_weighted<T:Clone>(&mut self, v: &[Weighted<T>]) -> T {
+ self.choose_weighted_option(v).expect("Rng.choose_weighted: total weight is 0")
+ }
+
+ /// Choose Some(item) respecting the relative weights, returning none if
+ /// the sum of the weights is 0
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ /// use std::rand::Rng;
+ ///
+ /// fn main() {
+ /// let mut rng = rand::rng();
+ /// let x = [rand::Weighted {weight: 4, item: 'a'},
+ /// rand::Weighted {weight: 2, item: 'b'},
+ /// rand::Weighted {weight: 2, item: 'c'}];
+ /// printfln!(rng.choose_weighted_option(x));
+ /// }
+ /// ~~~
+ fn choose_weighted_option<T:Clone>(&mut self, v: &[Weighted<T>])
+ -> Option<T> {
+ let mut total = 0u;
+ for item in v.iter() {
+ total += item.weight;
+ }
+ if total == 0u {
+ return None;
+ }
+ let chosen = self.gen_integer_range(0u, total);
+ let mut so_far = 0u;
+ for item in v.iter() {
+ so_far += item.weight;
+ if so_far > chosen {
+ return Some(item.item.clone());
+ }
+ }
+ unreachable!();
+ }
+
+ /// Return a vec containing copies of the items, in order, where
+ /// the weight of the item determines how many copies there are
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ /// use std::rand::Rng;
+ ///
+ /// fn main() {
+ /// let mut rng = rand::rng();
+ /// let x = [rand::Weighted {weight: 4, item: 'a'},
+ /// rand::Weighted {weight: 2, item: 'b'},
+ /// rand::Weighted {weight: 2, item: 'c'}];
+ /// printfln!(rng.weighted_vec(x));
+ /// }
+ /// ~~~
+ fn weighted_vec<T:Clone>(&mut self, v: &[Weighted<T>]) -> ~[T] {
+ let mut r = ~[];
+ for item in v.iter() {
+ for _ in range(0u, item.weight) {
+ r.push(item.item.clone());
+ }
+ }
+ r
+ }
+
+ /// Shuffle a vec
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ ///
+ /// fn main() {
+ /// printfln!(rand::task_rng().shuffle(~[1,2,3]));
+ /// }
+ /// ~~~
+ fn shuffle<T>(&mut self, values: ~[T]) -> ~[T] {
+ let mut v = values;
+ self.shuffle_mut(v);
+ v
+ }
+
+ /// Shuffle a mutable vector in place.
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ ///
+ /// fn main() {
+ /// let rng = rand::task_rng();
+ /// let mut y = [1,2,3];
+ /// rng.shuffle_mut(y);
+ /// printfln!(y);
+ /// rng.shuffle_mut(y);
+ /// printfln!(y);
+ /// }
+ /// ~~~
+ fn shuffle_mut<T>(&mut self, values: &mut [T]) {
+ let mut i = values.len();
+ while i >= 2u {
+ // invariant: elements with index >= i have been locked in place.
+ i -= 1u;
+ // lock element i in place.
+ values.swap(i, self.gen_integer_range(0u, i + 1u));
+ }
+ }
+
+ /// Randomly sample up to `n` elements from an iterator.
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// use std::rand;
+ ///
+ /// fn main() {
+ /// let rng = rand::task_rng();
+ /// let sample = rng.sample(range(1, 100), 5);
+ /// printfln!(sample);
+ /// }
+ /// ~~~
+ fn sample<A, T: Iterator<A>>(&mut self, iter: T, n: uint) -> ~[A] {
+ let mut reservoir : ~[A] = vec::with_capacity(n);
+ for (i, elem) in iter.enumerate() {
+ if i < n {
+ reservoir.push(elem);
+ loop
+ }
+
+ let k = self.gen_integer_range(0, i + 1);
+ if k < reservoir.len() {
+ reservoir[k] = elem
+ }
+ }
+ reservoir
+ }
+}
+
+/// Create a random number generator with a default algorithm and seed.
+///
+/// It returns the cryptographically-safest `Rng` algorithm currently
+/// available in Rust. If you require a specifically seeded `Rng` for
+/// consistency over time you should pick one algorithm and create the
+/// `Rng` yourself.
+pub fn rng() -> IsaacRng {
+ IsaacRng::new()
+}
+
+/// Create a weak random number generator with a default algorithm and seed.
+///
+/// It returns the fastest `Rng` algorithm currently available in Rust without
+/// consideration for cryptography or security. If you require a specifically
+/// seeded `Rng` for consistency over time you should pick one algorithm and
+/// create the `Rng` yourself.
+pub fn weak_rng() -> XorShiftRng {
+ XorShiftRng::new()
+}
+
+static RAND_SIZE_LEN: u32 = 8;
+static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
+
+/// A random number generator that uses the [ISAAC
+/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
+///
+/// The ISAAC algorithm is suitable for cryptographic purposes.
+pub struct IsaacRng {
+ priv cnt: u32,
+ priv rsl: [u32, .. RAND_SIZE],
+ priv mem: [u32, .. RAND_SIZE],
+ priv a: u32,
+ priv b: u32,
+ priv c: u32
+}
+
+impl IsaacRng {
+ /// Create an ISAAC random number generator with a random seed.
+ pub fn new() -> IsaacRng {
+ IsaacRng::new_seeded(seed())
+ }
+
+ /// Create an ISAAC random number generator with a seed. This can be any
+ /// length, although the maximum number of bytes used is 1024 and any more
+ /// will be silently ignored. A generator constructed with a given seed
+ /// will generate the same sequence of values as all other generators
+ /// constructed with the same seed.
+ pub fn new_seeded(seed: &[u8]) -> IsaacRng {
+ let mut rng = IsaacRng {
+ cnt: 0,
+ rsl: [0, .. RAND_SIZE],
+ mem: [0, .. RAND_SIZE],
+ a: 0, b: 0, c: 0
+ };
+
+ let array_size = sys::size_of_val(&rng.rsl);
+ let copy_length = cmp::min(array_size, seed.len());
+
+ // manually create a &mut [u8] slice of randrsl to copy into.
+ let dest = unsafe { cast::transmute((&mut rng.rsl, array_size)) };
+ vec::bytes::copy_memory(dest, seed, copy_length);
+ rng.init(true);
+ rng
+ }
+
+ /// Create an ISAAC random number generator using the default
+ /// fixed seed.
+ pub fn new_unseeded() -> IsaacRng {
+ let mut rng = IsaacRng {
+ cnt: 0,
+ rsl: [0, .. RAND_SIZE],
+ mem: [0, .. RAND_SIZE],
+ a: 0, b: 0, c: 0
+ };
+ rng.init(false);
+ rng
+ }
+
+ /// Initialises `self`. If `use_rsl` is true, then use the current value
+ /// of `rsl` as a seed, otherwise construct one algorithmically (not
+ /// randomly).
+ fn init(&mut self, use_rsl: bool) {
+ let mut a = 0x9e3779b9;
+ let mut b = a;
+ let mut c = a;
+ let mut d = a;
+ let mut e = a;
+ let mut f = a;
+ let mut g = a;
+ let mut h = a;
+
+ macro_rules! mix(
+ () => {{
+ a^=b<<11; d+=a; b+=c;
+ b^=c>>2; e+=b; c+=d;
+ c^=d<<8; f+=c; d+=e;
+ d^=e>>16; g+=d; e+=f;
+ e^=f<<10; h+=e; f+=g;
+ f^=g>>4; a+=f; g+=h;
+ g^=h<<8; b+=g; h+=a;
+ h^=a>>9; c+=h; a+=b;
+ }}
+ );
+
+ do 4.times { mix!(); }
+
+ if use_rsl {
+ macro_rules! memloop (
+ ($arr:expr) => {{
+ for i in range_step(0u32, RAND_SIZE, 8) {
+ a+=$arr[i ]; b+=$arr[i+1];
+ c+=$arr[i+2]; d+=$arr[i+3];
+ e+=$arr[i+4]; f+=$arr[i+5];
+ g+=$arr[i+6]; h+=$arr[i+7];
+ mix!();
+ self.mem[i ]=a; self.mem[i+1]=b;
+ self.mem[i+2]=c; self.mem[i+3]=d;
+ self.mem[i+4]=e; self.mem[i+5]=f;
+ self.mem[i+6]=g; self.mem[i+7]=h;
+ }
+ }}
+ );
+
+ memloop!(self.rsl);
+ memloop!(self.mem);
+ } else {
+ for i in range_step(0u32, RAND_SIZE, 8) {
+ mix!();
+ self.mem[i ]=a; self.mem[i+1]=b;
+ self.mem[i+2]=c; self.mem[i+3]=d;
+ self.mem[i+4]=e; self.mem[i+5]=f;
+ self.mem[i+6]=g; self.mem[i+7]=h;
+ }
+ }
+
+ self.isaac();
+ }
+
+ /// Refills the output buffer (`self.rsl`)
+ #[inline]
+ fn isaac(&mut self) {
+ self.c += 1;
+ // abbreviations
+ let mut a = self.a;
+ let mut b = self.b + self.c;
+
+ static MIDPOINT: uint = RAND_SIZE as uint / 2;
+
+ macro_rules! ind (($x:expr) => {
+ self.mem[($x >> 2) & (RAND_SIZE - 1)]
+ });
+ macro_rules! rngstep(
+ ($j:expr, $shift:expr) => {{
+ let base = $j;
+ let mix = if $shift < 0 {
+ a >> -$shift as uint
+ } else {
+ a << $shift as uint
+ };
+
+ let x = self.mem[base + mr_offset];
+ a = (a ^ mix) + self.mem[base + m2_offset];
+ let y = ind!(x) + a + b;
+ self.mem[base + mr_offset] = y;
+
+ b = ind!(y >> RAND_SIZE_LEN) + x;
+ self.rsl[base + mr_offset] = b;
+ }}
+ );
+
+ let r = [(0, MIDPOINT), (MIDPOINT, 0)];
+ for &(mr_offset, m2_offset) in r.iter() {
+ for i in range_step(0u, MIDPOINT, 4) {
+ rngstep!(i + 0, 13);
+ rngstep!(i + 1, -6);
+ rngstep!(i + 2, 2);
+ rngstep!(i + 3, -16);
+ }
+ }
+
+ self.a = a;
+ self.b = b;
+ self.cnt = RAND_SIZE;
+ }
+}
+
+impl Rng for IsaacRng {
+ #[inline]
+ fn next(&mut self) -> u32 {
+ if self.cnt == 0 {
+ // make some more numbers
+ self.isaac();
+ }
+ self.cnt -= 1;
+ self.rsl[self.cnt]
+ }
+}
+
+/// An [Xorshift random number
+/// generator](http://en.wikipedia.org/wiki/Xorshift).
+///
+/// The Xorshift algorithm is not suitable for cryptographic purposes
+/// but is very fast. If you do not know for sure that it fits your
+/// requirements, use a more secure one such as `IsaacRng`.
+pub struct XorShiftRng {
+ priv x: u32,
+ priv y: u32,
+ priv z: u32,
+ priv w: u32,
+}
+
+impl Rng for XorShiftRng {
+ #[inline]
+ fn next(&mut self) -> u32 {
+ let x = self.x;
+ let t = x ^ (x << 11);
+ self.x = self.y;
+ self.y = self.z;
+ self.z = self.w;
+ let w = self.w;
+ self.w = w ^ (w >> 19) ^ (t ^ (t >> 8));
+ self.w
+ }
+}
+
+impl XorShiftRng {
+ /// Create an xor shift random number generator with a random seed.
+ pub fn new() -> XorShiftRng {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ // generate seeds the same way as seed(), except we have a spceific size
+ let mut s = [0u8, ..16];
+ loop {
+ do s.as_mut_buf |p, sz| {
+ unsafe {
+ rustrt::rand_gen_seed(p, sz as size_t);
+ }
+ }
+ if !s.iter().all(|x| *x == 0) {
+ break;
+ }
+ }
+ let s: &[u32, ..4] = unsafe { cast::transmute(&s) };
+ XorShiftRng::new_seeded(s[0], s[1], s[2], s[3])
+ }
+
+ /**
+ * Create a random number generator using the specified seed. A generator
+ * constructed with a given seed will generate the same sequence of values
+ * as all other generators constructed with the same seed.
+ */
+ pub fn new_seeded(x: u32, y: u32, z: u32, w: u32) -> XorShiftRng {
+ XorShiftRng {
+ x: x,
+ y: y,
+ z: z,
+ w: w,
+ }
+ }
+}
+
+/// Create a new random seed.
+pub fn seed() -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ unsafe {
+ let n = RAND_SIZE * 4;
+ let mut s = vec::from_elem(n as uint, 0_u8);
+ do s.as_mut_buf |p, sz| {
+ rustrt::rand_gen_seed(p, sz as size_t)
+ }
+ s
+ }
+}
+
+// used to make space in TLS for a random number generator
+local_data_key!(tls_rng_state: @@mut IsaacRng)
+
+/**
+ * Gives back a lazily initialized task-local random number generator,
+ * seeded by the system. Intended to be used in method chaining style, ie
+ * `task_rng().gen::<int>()`.
+ */
+#[inline]
+pub fn task_rng() -> @mut IsaacRng {
+ let r = local_data::get(tls_rng_state, |k| k.map(|&k| *k));
+ match r {
+ None => {
+ let rng = @@mut IsaacRng::new_seeded(seed());
+ local_data::set(tls_rng_state, rng);
+ *rng
+ }
+ Some(rng) => *rng
+ }
+}
+
+// Allow direct chaining with `task_rng`
+impl<R: Rng> Rng for @mut R {
+ #[inline]
+ fn next(&mut self) -> u32 {
+ (**self).next()
+ }
+}
+
+/**
+ * Returns a random value of a Rand type, using the task's random number
+ * generator.
+ */
+#[inline]
+pub fn random<T: Rand>() -> T {
+ task_rng().gen()
+}
+
+#[cfg(test)]
+mod test {
+ use iter::{Iterator, range};
+ use option::{Option, Some};
+ use super::*;
+
+ #[test]
+ fn test_rng_seeded() {
+ let seed = seed();
+ let mut ra = IsaacRng::new_seeded(seed);
+ let mut rb = IsaacRng::new_seeded(seed);
+ assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
+ }
+
+ #[test]
+ fn test_rng_seeded_custom_seed() {
+ // much shorter than generated seeds which are 1024 bytes
+ let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
+ let mut ra = IsaacRng::new_seeded(seed);
+ let mut rb = IsaacRng::new_seeded(seed);
+ assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
+ }
+
+ #[test]
+ fn test_rng_seeded_custom_seed2() {
+ let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
+ let mut ra = IsaacRng::new_seeded(seed);
+ // Regression test that isaac is actually using the above vector
+ let r = ra.next();
+ error!("%?", r);
+ assert!(r == 890007737u32 // on x86_64
+ || r == 2935188040u32); // on x86
+ }
+
+ #[test]
+ fn test_gen_integer_range() {
+ let mut r = rng();
+ for _ in range(0, 1000) {
+ let a = r.gen_integer_range(-3i, 42);
+ assert!(a >= -3 && a < 42);
+ assert_eq!(r.gen_integer_range(0, 1), 0);
+ assert_eq!(r.gen_integer_range(-12, -11), -12);
+ }
+
+ for _ in range(0, 1000) {
+ let a = r.gen_integer_range(10, 42);
+ assert!(a >= 10 && a < 42);
+ assert_eq!(r.gen_integer_range(0, 1), 0);
+ assert_eq!(r.gen_integer_range(3_000_000u, 3_000_001), 3_000_000);
+ }
+
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_gen_integer_range_fail_int() {
+ let mut r = rng();
+ r.gen_integer_range(5i, -2);
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_gen_integer_range_fail_uint() {
+ let mut r = rng();
+ r.gen_integer_range(5u, 2u);
+ }
+
+ #[test]
+ fn test_gen_float() {
+ let mut r = rng();
+ let a = r.gen::<float>();
+ let b = r.gen::<float>();
+ debug!((a, b));
+ }
+
+ #[test]
+ fn test_gen_weighted_bool() {
+ let mut r = rng();
+ assert_eq!(r.gen_weighted_bool(0u), true);
+ assert_eq!(r.gen_weighted_bool(1u), true);
+ }
+
+ #[test]
+ fn test_gen_ascii_str() {
+ let mut r = rng();
+ debug!(r.gen_ascii_str(10u));
+ debug!(r.gen_ascii_str(10u));
+ debug!(r.gen_ascii_str(10u));
+ assert_eq!(r.gen_ascii_str(0u).len(), 0u);
+ assert_eq!(r.gen_ascii_str(10u).len(), 10u);
+ assert_eq!(r.gen_ascii_str(16u).len(), 16u);
+ }
+
+ #[test]
+ fn test_gen_vec() {
+ let mut r = rng();
+ assert_eq!(r.gen_vec::<u8>(0u).len(), 0u);
+ assert_eq!(r.gen_vec::<u8>(10u).len(), 10u);
+ assert_eq!(r.gen_vec::<f64>(16u).len(), 16u);
+ }
+
+ #[test]
+ fn test_choose() {
+ let mut r = rng();
+ assert_eq!(r.choose([1, 1, 1]), 1);
+ }
+
+ #[test]
+ fn test_choose_option() {
+ let mut r = rng();
+ let v: &[int] = &[];
+ assert!(r.choose_option(v).is_none());
+
+ let i = 1;
+ let v = [1,1,1];
+ assert_eq!(r.choose_option(v), Some(&i));
+ }
+
+ #[test]
+ fn test_choose_weighted() {
+ let mut r = rng();
+ assert!(r.choose_weighted([
+ Weighted { weight: 1u, item: 42 },
+ ]) == 42);
+ assert!(r.choose_weighted([
+ Weighted { weight: 0u, item: 42 },
+ Weighted { weight: 1u, item: 43 },
+ ]) == 43);
+ }
+
+ #[test]
+ fn test_choose_weighted_option() {
+ let mut r = rng();
+ assert!(r.choose_weighted_option([
+ Weighted { weight: 1u, item: 42 },
+ ]) == Some(42));
+ assert!(r.choose_weighted_option([
+ Weighted { weight: 0u, item: 42 },
+ Weighted { weight: 1u, item: 43 },
+ ]) == Some(43));
+ let v: Option<int> = r.choose_weighted_option([]);
+ assert!(v.is_none());
+ }
+
+ #[test]
+ fn test_weighted_vec() {
+ let mut r = rng();
+ let empty: ~[int] = ~[];
+ assert_eq!(r.weighted_vec([]), empty);
+ assert!(r.weighted_vec([
+ Weighted { weight: 0u, item: 3u },
+ Weighted { weight: 1u, item: 2u },
+ Weighted { weight: 2u, item: 1u },
+ ]) == ~[2u, 1u, 1u]);
+ }
+
+ #[test]
+ fn test_shuffle() {
+ let mut r = rng();
+ let empty: ~[int] = ~[];
+ assert_eq!(r.shuffle(~[]), empty);
+ assert_eq!(r.shuffle(~[1, 1, 1]), ~[1, 1, 1]);
+ }
+
+ #[test]
+ fn test_task_rng() {
+ let mut r = task_rng();
+ r.gen::<int>();
+ assert_eq!(r.shuffle(~[1, 1, 1]), ~[1, 1, 1]);
+ assert_eq!(r.gen_integer_range(0u, 1u), 0u);
+ }
+
+ #[test]
+ fn test_random() {
+ // not sure how to test this aside from just getting some values
+ let _n : uint = random();
+ let _f : f32 = random();
+ let _o : Option<Option<i8>> = random();
+ let _many : ((),
+ (~uint, @int, ~Option<~(@u32, ~(@bool,))>),
+ (u8, i8, u16, i16, u32, i32, u64, i64),
+ (f32, (f64, (float,)))) = random();
+ }
+
+ #[test]
+ fn test_sample() {
+ let MIN_VAL = 1;
+ let MAX_VAL = 100;
+
+ let mut r = rng();
+ let vals = range(MIN_VAL, MAX_VAL).to_owned_vec();
+ let small_sample = r.sample(vals.iter(), 5);
+ let large_sample = r.sample(vals.iter(), vals.len() + 5);
+
+ assert_eq!(small_sample.len(), 5);
+ assert_eq!(large_sample.len(), vals.len());
+
+ assert!(small_sample.iter().all(|e| {
+ **e >= MIN_VAL && **e <= MAX_VAL
+ }));
+ }
+}
+
+#[cfg(test)]
+mod bench {
+ use extra::test::BenchHarness;
+ use rand::*;
+ use sys::size_of;
+
+ #[bench]
+ fn rand_xorshift(bh: &mut BenchHarness) {
+ let mut rng = XorShiftRng::new();
+ do bh.iter {
+ rng.gen::<uint>();
+ }
+ bh.bytes = size_of::<uint>() as u64;
+ }
+
+ #[bench]
+ fn rand_isaac(bh: &mut BenchHarness) {
+ let mut rng = IsaacRng::new();
+ do bh.iter {
+ rng.gen::<uint>();
+ }
+ bh.bytes = size_of::<uint>() as u64;
+ }
+
+ #[bench]
+ fn rand_shuffle_100(bh: &mut BenchHarness) {
+ let mut rng = XorShiftRng::new();
+ let x : &mut[uint] = [1,..100];
+ do bh.iter {
+ rng.shuffle_mut(x);
+ }
+ }
+}
#[test]
fn megapipe_stress() {
use rand;
- use rand::RngUtil;
+ use rand::Rng;
if util::limit_thread_creation_due_to_osx_and_valgrind() { return; }
let total = stress_factor() + 10;
let mut rng = rand::rng();
do total.times {
- let msgs = rng.gen_uint_range(0, 10);
+ let msgs = rng.gen_integer_range(0u, 10);
let pipe_clone = pipe.clone();
let end_chan_clone = end_chan.clone();
do spawntask_random {
use rt::rtio::{RemoteCallback, PausibleIdleCallback};
use borrow::{to_uint};
use cell::Cell;
-use rand::{XorShiftRng, RngUtil};
+use rand::{XorShiftRng, Rng};
use iter::range;
use vec::{OwnedVector};
fn try_steals(&mut self) -> Option<~Task> {
let work_queues = &mut self.work_queues;
let len = work_queues.len();
- let start_index = self.rng.gen_uint_range(0, len);
+ let start_index = self.rng.gen_integer_range(0, len);
for index in range(0, len).map(|i| (i + start_index) % len) {
match work_queues[index].steal() {
Some(task) => {
#[test]
fn dont_starve_1() {
use rt::comm::oneshot;
+ use unstable::running_on_valgrind;
- do stress_factor().times {
- do run_in_mt_newsched_task {
- let (port, chan) = oneshot();
+ // FIXME: #9407: should work while serialized on valgrind
+ if !running_on_valgrind() {
+ do stress_factor().times {
+ do run_in_mt_newsched_task {
+ let (port, chan) = oneshot();
- // This task should not be able to starve the sender;
- // The sender should get stolen to another thread.
- do spawntask {
- while !port.peek() { }
- }
+ // This task should not be able to starve the sender;
+ // The sender should get stolen to another thread.
+ do spawntask {
+ while !port.peek() { }
+ }
- chan.send(());
+ chan.send(());
+ }
}
}
}
#[link(name = "std",
- vers = "0.8-pre",
+ vers = "0.8",
uuid = "c70c24a7-5551-4f73-8e37-380b11d80be8",
url = "https://github.com/mozilla/rust/tree/master/src/libstd")];
#[deny(missing_doc)];
// Make extra accessible for benchmarking
-#[cfg(test)] extern mod extra(vers="0.8-pre");
+#[cfg(test)] extern mod extra(vers="0.8");
// Make std testable by not duplicating lang items. See #2912
#[cfg(test)] extern mod realstd(name = "std");
*/
#[link(name = "syntax",
- vers = "0.8-pre",
+ vers = "0.8",
uuid = "9311401b-d6ea-4cd9-a1d9-61f89499c645")];
#[license = "MIT/ASL2"];
+++ /dev/null
-/*
-------------------------------------------------------------------------------
-rand.h: definitions for a random number generator
-By Bob Jenkins, 1996, Public Domain
-MODIFIED:
- 960327: Creation (addition of randinit, really)
- 970719: use context, not global variables, for internal state
- 980324: renamed seed to flag
- 980605: recommend RANDSIZL=4 for noncryptography.
- 010626: note this is public domain
-------------------------------------------------------------------------------
-*/
-#ifndef STANDARD
-#include "standard.h"
-#endif
-
-#ifndef RAND
-#define RAND
-#define RANDSIZL (8) /* I recommend 8 for crypto, 4 for simulations */
-#define RANDSIZ (1<<RANDSIZL)
-
-/* context of random number generator */
-struct randctx
-{
- ub4 randcnt;
- ub4 randrsl[RANDSIZ];
- ub4 randmem[RANDSIZ];
- ub4 randa;
- ub4 randb;
- ub4 randc;
-};
-typedef struct randctx randctx;
-
-/*
-------------------------------------------------------------------------------
- If (flag==TRUE), then use the contents of randrsl[0..RANDSIZ-1] as the seed.
-------------------------------------------------------------------------------
-*/
-void randinit(randctx *r, word flag);
-
-void isaac(randctx *r);
-
-
-/*
-------------------------------------------------------------------------------
- Call isaac_rand(/o_ randctx *r _o/) to retrieve a single 32-bit random value
-------------------------------------------------------------------------------
-*/
-#define isaac_rand(r) \
- (!(r)->randcnt-- ? \
- (isaac(r), (r)->randcnt=RANDSIZ-1, (r)->randrsl[(r)->randcnt]) : \
- (r)->randrsl[(r)->randcnt])
-
-#endif /* RAND */
+++ /dev/null
-/*
-------------------------------------------------------------------------------
-rand.c: By Bob Jenkins. My random number generator, ISAAC. Public Domain
-MODIFIED:
- 960327: Creation (addition of randinit, really)
- 970719: use context, not global variables, for internal state
- 980324: make a portable version
- 010626: Note this is public domain
- 100725: Mask on use of >32 bits, not on assignment: from Paul Eggert
-------------------------------------------------------------------------------
-*/
-#ifndef STANDARD
-#include "standard.h"
-#endif
-#ifndef RAND
-#include "rand.h"
-#endif
-
-
-#define ind(mm,x) ((mm)[(x>>2)&(RANDSIZ-1)])
-#define rngstep(mix,a,b,mm,m,m2,r,x) \
-{ \
- x = *m; \
- a = ((a^(mix)) + *(m2++)) & 0xffffffff; \
- *(m++) = y = (ind(mm,x) + a + b) & 0xffffffff; \
- *(r++) = b = (ind(mm,y>>RANDSIZL) + x) & 0xffffffff; \
-}
-
-void isaac(randctx *ctx)
-{
- ub4 a,b,x,y,*m,*mm,*m2,*r,*mend;
- mm=ctx->randmem; r=ctx->randrsl;
- a = ctx->randa; b = ctx->randb + (++ctx->randc);
- for (m = mm, mend = m2 = m+(RANDSIZ/2); m<mend; )
- {
- rngstep( a<<13, a, b, mm, m, m2, r, x);
- rngstep( (a & 0xffffffff) >>6 , a, b, mm, m, m2, r, x);
- rngstep( a<<2 , a, b, mm, m, m2, r, x);
- rngstep( (a & 0xffffffff) >>16, a, b, mm, m, m2, r, x);
- }
- for (m2 = mm; m2<mend; )
- {
- rngstep( a<<13, a, b, mm, m, m2, r, x);
- rngstep( (a & 0xffffffff) >>6 , a, b, mm, m, m2, r, x);
- rngstep( a<<2 , a, b, mm, m, m2, r, x);
- rngstep( (a & 0xffffffff) >>16, a, b, mm, m, m2, r, x);
- }
- ctx->randb = b; ctx->randa = a;
-}
-
-
-#define mix(a,b,c,d,e,f,g,h) \
-{ \
- a^=b<<11; d+=a; b+=c; \
- b^=(c&0xffffffff)>>2; e+=b; c+=d; \
- c^=d<<8; f+=c; d+=e; \
- d^=(e&0xffffffff)>>16; g+=d; e+=f; \
- e^=f<<10; h+=e; f+=g; \
- f^=(g&0xffffffff)>>4; a+=f; g+=h; \
- g^=h<<8; b+=g; h+=a; \
- h^=(a&0xffffffff)>>9; c+=h; a+=b; \
-}
-
-/* if (flag==TRUE), then use the contents of randrsl[] to initialize mm[]. */
-void randinit(randctx *ctx, word flag)
-{
- word i;
- ub4 a,b,c,d,e,f,g,h;
- ub4 *m,*r;
- ctx->randa = ctx->randb = ctx->randc = 0;
- m=ctx->randmem;
- r=ctx->randrsl;
- a=b=c=d=e=f=g=h=0x9e3779b9; /* the golden ratio */
-
- for (i=0; i<4; ++i) /* scramble it */
- {
- mix(a,b,c,d,e,f,g,h);
- }
-
- if (flag)
- {
- /* initialize using the contents of r[] as the seed */
- for (i=0; i<RANDSIZ; i+=8)
- {
- a+=r[i ]; b+=r[i+1];
- c+=r[i+2]; d+=r[i+3];
- e+=r[i+4]; f+=r[i+5];
- g+=r[i+6]; h+=r[i+7];
- mix(a,b,c,d,e,f,g,h);
- m[i ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
- m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
- }
- /* do a second pass to make all of the seed affect all of m */
- for (i=0; i<RANDSIZ; i+=8)
- {
- a+=m[i ]; b+=m[i+1];
- c+=m[i+2]; d+=m[i+3];
- e+=m[i+4]; f+=m[i+5];
- g+=m[i+6]; h+=m[i+7];
- mix(a,b,c,d,e,f,g,h);
- m[i ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
- m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
- }
- }
- else
- {
- for (i=0; i<RANDSIZ; i+=8)
- {
- /* fill in mm[] with messy stuff */
- mix(a,b,c,d,e,f,g,h);
- m[i ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
- m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
- }
- }
-
- isaac(ctx); /* fill in the first set of results */
- ctx->randcnt=RANDSIZ; /* prepare to use the first set of results */
-}
-
-
-#ifdef NEVER
-int main()
-{
- ub4 i,j;
- randctx ctx;
- ctx.randa=ctx.randb=ctx.randc=(ub4)0;
- for (i=0; i<256; ++i) ctx.randrsl[i]=(ub4)0;
- randinit(&ctx, TRUE);
- for (i=0; i<2; ++i)
- {
- isaac(&ctx);
- for (j=0; j<256; ++j)
- {
- printf("%.8lx",ctx.randrsl[j]);
- if ((j&7)==7) printf("\n");
- }
- }
-}
-#endif
+++ /dev/null
-/*
-------------------------------------------------------------------------------
-Standard definitions and types, Bob Jenkins
-------------------------------------------------------------------------------
-*/
-#ifndef STANDARD
-# define STANDARD
-# ifndef STDIO
-# include <stdio.h>
-# define STDIO
-# endif
-# ifndef STDDEF
-# include <stddef.h>
-# define STDDEF
-# endif
-# ifndef STDINT
-# include <stdint.h>
-# define STDINT
-# endif
-
-typedef uint64_t ub8;
-#define UB8MAXVAL 0xffffffffffffffffLL
-#define UB8BITS 64
-typedef int64_t sb8;
-#define SB8MAXVAL 0x7fffffffffffffffLL
-typedef uint32_t ub4; /* unsigned 4-byte quantities */
-#define UB4MAXVAL 0xffffffff
-typedef int32_t sb4;
-#define UB4BITS 32
-#define SB4MAXVAL 0x7fffffff
-typedef uint16_t ub2;
-#define UB2MAXVAL 0xffff
-#define UB2BITS 16
-typedef int16_t sb2;
-#define SB2MAXVAL 0x7fff
-typedef uint8_t ub1;
-#define UB1MAXVAL 0xff
-#define UB1BITS 8
-typedef int8_t sb1; /* signed 1-byte quantities */
-#define SB1MAXVAL 0x7f
-typedef int word; /* fastest type available */
-
-#define bis(target,mask) ((target) |= (mask))
-#define bic(target,mask) ((target) &= ~(mask))
-#define bit(target,mask) ((target) & (mask))
-#define TRUE 1
-#define FALSE 0
-#define SUCCESS 0 /* 1 on VAX */
-
-#endif /* STANDARD */
}
#endif
-extern "C" CDECL size_t
-rand_seed_size() {
- return rng_seed_size();
-}
-
extern "C" CDECL void
rand_gen_seed(uint8_t* dest, size_t size) {
rng_gen_seed(dest, size);
}
-extern "C" CDECL void *
-rand_new_seeded(uint8_t* seed, size_t seed_size) {
- assert(seed != NULL);
- rust_rng *rng = (rust_rng *) malloc(sizeof(rust_rng));
- assert(rng != NULL && "rng alloc failed");
- rng_init(rng, NULL, seed, seed_size);
- return rng;
-}
-
-extern "C" CDECL uint32_t
-rand_next(rust_rng *rng) {
- return rng_gen_u32(rng);
-}
-
-extern "C" CDECL void
-rand_free(rust_rng *rng) {
- free(rng);
-}
-
extern "C" CDECL char*
#if defined(__WIN32__)
rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) {
}
#endif
-size_t
-rng_seed_size() {
- randctx rctx;
- return sizeof(rctx.randrsl);
-}
-
-// Initialization helpers for ISAAC RNG
-
void
rng_gen_seed(uint8_t* dest, size_t size) {
#ifdef __WIN32__
#endif
}
-static void
-isaac_init(randctx *rctx, char *env_seed,
- uint8_t* user_seed, size_t seed_len) {
- memset(rctx, 0, sizeof(randctx));
-
- if (user_seed != NULL) {
- // ignore bytes after the required length
- if (seed_len > sizeof(rctx->randrsl)) {
- seed_len = sizeof(rctx->randrsl);
- }
- memcpy(&rctx->randrsl, user_seed, seed_len);
- } else if (env_seed != NULL) {
- ub4 seed = (ub4) atoi(env_seed);
- for (size_t i = 0; i < RANDSIZ; i ++) {
- memcpy(&rctx->randrsl[i], &seed, sizeof(ub4));
- seed = (seed + 0x7ed55d16) + (seed << 12);
- }
- } else {
- rng_gen_seed((uint8_t*)&rctx->randrsl,
- sizeof(rctx->randrsl));
- }
-
- randinit(rctx, 1);
-}
-
-void
-rng_init(rust_rng* rng, char* env_seed,
- uint8_t *user_seed, size_t seed_len) {
- isaac_init(&rng->rctx, env_seed, user_seed, seed_len);
- rng->reseedable = !user_seed && !env_seed;
-}
-
-static void
-rng_maybe_reseed(rust_rng* rng) {
- // If this RNG has generated more than 32KB of random data and was not
- // seeded by the user or RUST_SEED, then we should reseed now.
- const size_t RESEED_THRESHOLD = 32 * 1024;
- size_t bytes_generated = rng->rctx.randc * sizeof(ub4);
- if (bytes_generated < RESEED_THRESHOLD || !rng->reseedable) {
- return;
- }
- rng_gen_seed((uint8_t*)rng->rctx.randrsl,
- sizeof(rng->rctx.randrsl));
- randinit(&rng->rctx, 1);
-}
-
-uint32_t
-rng_gen_u32(rust_rng* rng) {
- uint32_t x = isaac_rand(&rng->rctx);
- rng_maybe_reseed(rng);
- return x;
-}
-
//
// Local Variables:
// mode: C++
#ifndef RUST_RNG_H
#define RUST_RNG_H
-#include "rand.h"
-
-class rust_kernel;
-
-// Initialization helpers for ISAAC RNG
-
-struct rust_rng {
- randctx rctx;
- bool reseedable;
-};
-
-size_t rng_seed_size();
void rng_gen_seed(uint8_t* dest, size_t size);
-void rng_init(rust_rng *rng, char *env_seed,
- uint8_t *user_seed, size_t seed_len);
-uint32_t rng_gen_u32(rust_rng *rng);
//
// Local Variables:
rust_timegm
rust_mktime
precise_time_ns
-rand_free
-rand_new_seeded
-rand_seed_size
rand_gen_seed
-rand_next
rust_path_is_dir
rust_path_exists
rust_get_stdin
+++ /dev/null
-*.swp
-main
+++ /dev/null
-// Copyright 2012-2013 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.
-
-//! This module contains the "cleaned" pieces of the AST, and the functions
-//! that clean them.
-
-use its = syntax::parse::token::ident_to_str;
-
-use syntax;
-use syntax::ast;
-use syntax::attr::AttributeMethods;
-
-use std;
-use doctree;
-use visit_ast;
-use std::local_data;
-
-pub trait Clean<T> {
- fn clean(&self) -> T;
-}
-
-impl<T: Clean<U>, U> Clean<~[U]> for ~[T] {
- fn clean(&self) -> ~[U] {
- self.iter().map(|x| x.clean()).collect()
- }
-}
-impl<T: Clean<U>, U> Clean<U> for @T {
- fn clean(&self) -> U {
- (**self).clean()
- }
-}
-
-impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
- fn clean(&self) -> Option<U> {
- match self {
- &None => None,
- &Some(ref v) => Some(v.clean())
- }
- }
-}
-
-impl<T: Clean<U>, U> Clean<~[U]> for syntax::opt_vec::OptVec<T> {
- fn clean(&self) -> ~[U] {
- match self {
- &syntax::opt_vec::Empty => ~[],
- &syntax::opt_vec::Vec(ref v) => v.clean()
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Crate {
- name: ~str,
- module: Option<Item>,
-}
-
-impl Clean<Crate> for visit_ast::RustdocVisitor {
- fn clean(&self) -> Crate {
- use syntax::attr::{find_linkage_metas, last_meta_item_value_str_by_name};
- let maybe_meta = last_meta_item_value_str_by_name(find_linkage_metas(self.attrs), "name");
-
- Crate {
- name: match maybe_meta {
- Some(x) => x.to_owned(),
- None => fail!("rustdoc_ng requires a #[link(name=\"foo\")] crate attribute"),
- },
- module: Some(self.module.clean()),
- }
- }
-}
-
-/// Anything with a source location and set of attributes and, optionally, a
-/// name. That is, anything that can be documented. This doesn't correspond
-/// directly to the AST's concept of an item; it's a strict superset.
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Item {
- /// Stringified span
- source: ~str,
- /// Not everything has a name. E.g., impls
- name: Option<~str>,
- attrs: ~[Attribute],
- inner: ItemEnum,
- visibility: Option<Visibility>,
- id: ast::NodeId,
-}
-
-impl Item {
- /// Finds the `doc` attribute as a List and returns the list of attributes
- /// nested inside.
- pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> {
- for attr in self.attrs.iter() {
- match *attr {
- List(~"doc", ref list) => { return Some(list.as_slice()); }
- _ => {}
- }
- }
- return None;
- }
-
- /// Finds the `doc` attribute as a NameValue and returns the corresponding
- /// value found.
- pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
- for attr in self.attrs.iter() {
- match *attr {
- NameValue(~"doc", ref v) => { return Some(v.as_slice()); }
- _ => {}
- }
- }
- return None;
- }
-
- pub fn is_mod(&self) -> bool {
- match self.inner { ModuleItem(*) => true, _ => false }
- }
- pub fn is_trait(&self) -> bool {
- match self.inner { TraitItem(*) => true, _ => false }
- }
- pub fn is_struct(&self) -> bool {
- match self.inner { StructItem(*) => true, _ => false }
- }
- pub fn is_enum(&self) -> bool {
- match self.inner { EnumItem(*) => true, _ => false }
- }
- pub fn is_fn(&self) -> bool {
- match self.inner { FunctionItem(*) => true, _ => false }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub enum ItemEnum {
- StructItem(Struct),
- EnumItem(Enum),
- FunctionItem(Function),
- ModuleItem(Module),
- TypedefItem(Typedef),
- StaticItem(Static),
- TraitItem(Trait),
- ImplItem(Impl),
- ViewItemItem(ViewItem),
- TyMethodItem(TyMethod),
- MethodItem(Method),
- StructFieldItem(StructField),
- VariantItem(Variant),
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Module {
- items: ~[Item],
-}
-
-impl Clean<Item> for doctree::Module {
- fn clean(&self) -> Item {
- let name = if self.name.is_some() {
- self.name.unwrap().clean()
- } else {
- ~""
- };
- Item {
- name: Some(name),
- attrs: self.attrs.clean(),
- source: self.where.clean(),
- visibility: self.vis.clean(),
- id: self.id,
- inner: ModuleItem(Module {
- items: std::vec::concat(&[self.structs.clean(),
- self.enums.clean(), self.fns.clean(),
- self.mods.clean(), self.typedefs.clean(),
- self.statics.clean(), self.traits.clean(),
- self.impls.clean(), self.view_items.clean()])
- })
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub enum Attribute {
- Word(~str),
- List(~str, ~[Attribute]),
- NameValue(~str, ~str)
-}
-
-impl Clean<Attribute> for ast::MetaItem {
- fn clean(&self) -> Attribute {
- match self.node {
- ast::MetaWord(s) => Word(s.to_owned()),
- ast::MetaList(ref s, ref l) => List(s.to_owned(), l.clean()),
- ast::MetaNameValue(s, ref v) => NameValue(s.to_owned(), lit_to_str(v))
- }
- }
-}
-
-impl Clean<Attribute> for ast::Attribute {
- fn clean(&self) -> Attribute {
- self.desugar_doc().node.value.clean()
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct TyParam {
- name: ~str,
- id: ast::NodeId,
- bounds: ~[TyParamBound]
-}
-
-impl Clean<TyParam> for ast::TyParam {
- fn clean(&self) -> TyParam {
- TyParam {
- name: self.ident.clean(),
- id: self.id,
- bounds: self.bounds.clean(),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub enum TyParamBound {
- RegionBound,
- TraitBound(Type)
-}
-
-impl Clean<TyParamBound> for ast::TyParamBound {
- fn clean(&self) -> TyParamBound {
- match *self {
- ast::RegionTyParamBound => RegionBound,
- ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Lifetime(~str);
-
-impl Clean<Lifetime> for ast::Lifetime {
- fn clean(&self) -> Lifetime {
- Lifetime(self.ident.clean())
- }
-}
-
-// maybe use a Generic enum and use ~[Generic]?
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Generics {
- lifetimes: ~[Lifetime],
- type_params: ~[TyParam]
-}
-
-impl Generics {
- fn new() -> Generics {
- Generics {
- lifetimes: ~[],
- type_params: ~[]
- }
- }
-}
-
-impl Clean<Generics> for ast::Generics {
- fn clean(&self) -> Generics {
- Generics {
- lifetimes: self.lifetimes.clean(),
- type_params: self.ty_params.clean(),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Method {
- generics: Generics,
- self_: SelfTy,
- purity: ast::purity,
- decl: FnDecl,
-}
-
-impl Clean<Item> for ast::method {
- fn clean(&self) -> Item {
- Item {
- name: Some(self.ident.clean()),
- attrs: self.attrs.clean(),
- source: self.span.clean(),
- id: self.self_id.clone(),
- visibility: None,
- inner: MethodItem(Method {
- generics: self.generics.clean(),
- self_: self.explicit_self.clean(),
- purity: self.purity.clone(),
- decl: self.decl.clean(),
- }),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct TyMethod {
- purity: ast::purity,
- decl: FnDecl,
- generics: Generics,
- self_: SelfTy,
-}
-
-impl Clean<Item> for ast::TypeMethod {
- fn clean(&self) -> Item {
- Item {
- name: Some(self.ident.clean()),
- attrs: self.attrs.clean(),
- source: self.span.clean(),
- id: self.id,
- visibility: None,
- inner: TyMethodItem(TyMethod {
- purity: self.purity.clone(),
- decl: self.decl.clean(),
- self_: self.explicit_self.clean(),
- generics: self.generics.clean(),
- }),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub enum SelfTy {
- SelfStatic,
- SelfValue,
- SelfBorrowed(Option<Lifetime>, Mutability),
- SelfManaged(Mutability),
- SelfOwned,
-}
-
-impl Clean<SelfTy> for ast::explicit_self {
- fn clean(&self) -> SelfTy {
- match self.node {
- ast::sty_static => SelfStatic,
- ast::sty_value => SelfValue,
- ast::sty_uniq => SelfOwned,
- ast::sty_region(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()),
- ast::sty_box(mt) => SelfManaged(mt.clean()),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Function {
- decl: FnDecl,
- generics: Generics,
-}
-
-impl Clean<Item> for doctree::Function {
- fn clean(&self) -> Item {
- Item {
- name: Some(self.name.clean()),
- attrs: self.attrs.clean(),
- source: self.where.clean(),
- visibility: self.vis.clean(),
- id: self.id,
- inner: FunctionItem(Function {
- decl: self.decl.clean(),
- generics: self.generics.clean(),
- }),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct ClosureDecl {
- sigil: ast::Sigil,
- region: Option<Lifetime>,
- lifetimes: ~[Lifetime],
- decl: FnDecl,
- onceness: ast::Onceness,
- purity: ast::purity,
- bounds: ~[TyParamBound]
-}
-
-impl Clean<ClosureDecl> for ast::TyClosure {
- fn clean(&self) -> ClosureDecl {
- ClosureDecl {
- sigil: self.sigil,
- region: self.region.clean(),
- lifetimes: self.lifetimes.clean(),
- decl: self.decl.clean(),
- onceness: self.onceness,
- purity: self.purity,
- bounds: match self.bounds {
- Some(ref x) => x.clean(),
- None => ~[]
- },
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct FnDecl {
- inputs: ~[Argument],
- output: Type,
- cf: RetStyle,
- attrs: ~[Attribute]
-}
-
-impl Clean<FnDecl> for ast::fn_decl {
- fn clean(&self) -> FnDecl {
- FnDecl {
- inputs: self.inputs.iter().map(|x| x.clean()).collect(),
- output: (self.output.clean()),
- cf: self.cf.clean(),
- attrs: ~[]
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Argument {
- type_: Type,
- name: ~str,
- id: ast::NodeId
-}
-
-impl Clean<Argument> for ast::arg {
- fn clean(&self) -> Argument {
- Argument {
- name: name_from_pat(self.pat),
- type_: (self.ty.clean()),
- id: self.id
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub enum RetStyle {
- NoReturn,
- Return
-}
-
-impl Clean<RetStyle> for ast::ret_style {
- fn clean(&self) -> RetStyle {
- match *self {
- ast::return_val => Return,
- ast::noreturn => NoReturn
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Trait {
- methods: ~[TraitMethod],
- generics: Generics,
- parents: ~[Type],
-}
-
-impl Clean<Item> for doctree::Trait {
- fn clean(&self) -> Item {
- Item {
- name: Some(self.name.clean()),
- attrs: self.attrs.clean(),
- source: self.where.clean(),
- id: self.id,
- visibility: self.vis.clean(),
- inner: TraitItem(Trait {
- methods: self.methods.clean(),
- generics: self.generics.clean(),
- parents: self.parents.clean(),
- }),
- }
- }
-}
-
-impl Clean<Type> for ast::trait_ref {
- fn clean(&self) -> Type {
- let t = Unresolved(self.path.clean(), None, self.ref_id);
- resolve_type(&t)
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub enum TraitMethod {
- Required(Item),
- Provided(Item),
-}
-
-impl TraitMethod {
- pub fn is_req(&self) -> bool {
- match self {
- &Required(*) => true,
- _ => false,
- }
- }
- pub fn is_def(&self) -> bool {
- match self {
- &Provided(*) => true,
- _ => false,
- }
- }
- pub fn item<'a>(&'a self) -> &'a Item {
- match *self {
- Required(ref item) => item,
- Provided(ref item) => item,
- }
- }
-}
-
-impl Clean<TraitMethod> for ast::trait_method {
- fn clean(&self) -> TraitMethod {
- match self {
- &ast::required(ref t) => Required(t.clean()),
- &ast::provided(ref t) => Provided(t.clean()),
- }
- }
-}
-
-/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
-/// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
-/// it does not preserve mutability or boxes.
-#[deriving(Clone, Encodable, Decodable)]
-pub enum Type {
- /// Most types start out as "Unresolved". It serves as an intermediate stage between cleaning
- /// and type resolution.
- Unresolved(Path, Option<~[TyParamBound]>, ast::NodeId),
- /// structs/enums/traits (anything that'd be an ast::ty_path)
- ResolvedPath { path: Path, typarams: Option<~[TyParamBound]>, id: ast::NodeId },
- /// Reference to an item in an external crate (fully qualified path)
- External(~str, ~str),
- // I have no idea how to usefully use this.
- TyParamBinder(ast::NodeId),
- /// For parameterized types, so the consumer of the JSON don't go looking
- /// for types which don't exist anywhere.
- Generic(ast::NodeId),
- /// For references to self
- Self(ast::NodeId),
- /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
- Primitive(ast::prim_ty),
- Closure(~ClosureDecl),
- /// extern "ABI" fn
- BareFunction(~BareFunctionDecl),
- Tuple(~[Type]),
- Vector(~Type),
- FixedVector(~Type, ~str),
- String,
- Bool,
- /// aka ty_nil
- Unit,
- /// aka ty_bot
- Bottom,
- Unique(~Type),
- Managed(Mutability, ~Type),
- RawPointer(Mutability, ~Type),
- BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: ~Type},
- // region, raw, other boxes, mutable
-}
-
-impl Clean<Type> for ast::Ty {
- fn clean(&self) -> Type {
- use syntax::ast::*;
- debug!("cleaning type `%?`", self);
- let codemap = local_data::get(super::ctxtkey, |x| *x.unwrap()).sess.codemap;
- debug!("span corresponds to `%s`", codemap.span_to_str(self.span));
- let t = match self.node {
- ty_nil => Unit,
- ty_ptr(ref m) => RawPointer(m.mutbl.clean(), ~resolve_type(&m.ty.clean())),
- ty_rptr(ref l, ref m) =>
- BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(),
- type_: ~resolve_type(&m.ty.clean())},
- ty_box(ref m) => Managed(m.mutbl.clean(), ~resolve_type(&m.ty.clean())),
- ty_uniq(ref m) => Unique(~resolve_type(&m.ty.clean())),
- ty_vec(ref m) => Vector(~resolve_type(&m.ty.clean())),
- ty_fixed_length_vec(ref m, ref e) => FixedVector(~resolve_type(&m.ty.clean()),
- e.span.to_src()),
- ty_tup(ref tys) => Tuple(tys.iter().map(|x| resolve_type(&x.clean())).collect()),
- ty_path(ref p, ref tpbs, id) => Unresolved(p.clean(), tpbs.clean(), id),
- ty_closure(ref c) => Closure(~c.clean()),
- ty_bare_fn(ref barefn) => BareFunction(~barefn.clean()),
- ty_bot => Bottom,
- ref x => fail!("Unimplemented type %?", x),
- };
- resolve_type(&t)
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct StructField {
- type_: Type,
-}
-
-impl Clean<Item> for ast::struct_field {
- fn clean(&self) -> Item {
- let (name, vis) = match self.node.kind {
- ast::named_field(id, vis) => (Some(id), Some(vis)),
- _ => (None, None)
- };
- Item {
- name: name.clean(),
- attrs: self.node.attrs.clean(),
- source: self.span.clean(),
- visibility: vis,
- id: self.node.id,
- inner: StructFieldItem(StructField {
- type_: self.node.ty.clean(),
- }),
- }
- }
-}
-
-pub type Visibility = ast::visibility;
-
-impl Clean<Option<Visibility>> for ast::visibility {
- fn clean(&self) -> Option<Visibility> {
- Some(*self)
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Struct {
- struct_type: doctree::StructType,
- generics: Generics,
- fields: ~[Item],
-}
-
-impl Clean<Item> for doctree::Struct {
- fn clean(&self) -> Item {
- Item {
- name: Some(self.name.clean()),
- attrs: self.attrs.clean(),
- source: self.where.clean(),
- id: self.id,
- visibility: self.vis.clean(),
- inner: StructItem(Struct {
- struct_type: self.struct_type,
- generics: self.generics.clean(),
- fields: self.fields.clean(),
- }),
- }
- }
-}
-
-/// This is a more limited form of the standard Struct, different in that it
-/// it lacks the things most items have (name, id, parameterization). Found
-/// only as a variant in an enum.
-#[deriving(Clone, Encodable, Decodable)]
-pub struct VariantStruct {
- struct_type: doctree::StructType,
- fields: ~[Item],
-}
-
-impl Clean<VariantStruct> for syntax::ast::struct_def {
- fn clean(&self) -> VariantStruct {
- VariantStruct {
- struct_type: doctree::struct_type_from_def(self),
- fields: self.fields.clean(),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Enum {
- variants: ~[Item],
- generics: Generics,
-}
-
-impl Clean<Item> for doctree::Enum {
- fn clean(&self) -> Item {
- Item {
- name: Some(self.name.clean()),
- attrs: self.attrs.clean(),
- source: self.where.clean(),
- id: self.id,
- visibility: self.vis.clean(),
- inner: EnumItem(Enum {
- variants: self.variants.clean(),
- generics: self.generics.clean(),
- }),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Variant {
- kind: VariantKind,
-}
-
-impl Clean<Item> for doctree::Variant {
- fn clean(&self) -> Item {
- Item {
- name: Some(self.name.clean()),
- attrs: self.attrs.clean(),
- source: self.where.clean(),
- visibility: self.vis.clean(),
- id: self.id,
- inner: VariantItem(Variant {
- kind: self.kind.clean(),
- }),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub enum VariantKind {
- CLikeVariant,
- TupleVariant(~[Type]),
- StructVariant(VariantStruct),
-}
-
-impl Clean<VariantKind> for ast::variant_kind {
- fn clean(&self) -> VariantKind {
- match self {
- &ast::tuple_variant_kind(ref args) => {
- if args.len() == 0 {
- CLikeVariant
- } else {
- TupleVariant(args.iter().map(|x| x.ty.clean()).collect())
- }
- },
- &ast::struct_variant_kind(ref sd) => StructVariant(sd.clean()),
- }
- }
-}
-
-impl Clean<~str> for syntax::codemap::Span {
- fn clean(&self) -> ~str {
- let cm = local_data::get(super::ctxtkey, |x| x.unwrap().clone()).sess.codemap;
- cm.span_to_str(*self)
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Path {
- global: bool,
- segments: ~[PathSegment],
-}
-
-impl Clean<Path> for ast::Path {
- fn clean(&self) -> Path {
- Path {
- global: self.global,
- segments: self.segments.clean()
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct PathSegment {
- name: ~str,
- lifetime: Option<Lifetime>,
- types: ~[Type],
-}
-
-impl Clean<PathSegment> for ast::PathSegment {
- fn clean(&self) -> PathSegment {
- PathSegment {
- name: self.identifier.clean(),
- lifetime: self.lifetime.clean(),
- types: self.types.clean()
- }
- }
-}
-
-fn path_to_str(p: &ast::Path) -> ~str {
- use syntax::parse::token::interner_get;
-
- let mut s = ~"";
- let mut first = true;
- for i in p.segments.iter().map(|x| interner_get(x.identifier.name)) {
- if !first || p.global {
- s.push_str("::");
- } else {
- first = false;
- }
- s.push_str(i);
- }
- s
-}
-
-impl Clean<~str> for ast::Ident {
- fn clean(&self) -> ~str {
- its(self).to_owned()
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Typedef {
- type_: Type,
- generics: Generics,
-}
-
-impl Clean<Item> for doctree::Typedef {
- fn clean(&self) -> Item {
- Item {
- name: Some(self.name.clean()),
- attrs: self.attrs.clean(),
- source: self.where.clean(),
- id: self.id.clone(),
- visibility: self.vis.clean(),
- inner: TypedefItem(Typedef {
- type_: self.ty.clean(),
- generics: self.gen.clean(),
- }),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct BareFunctionDecl {
- purity: ast::purity,
- generics: Generics,
- decl: FnDecl,
- abi: ~str
-}
-
-impl Clean<BareFunctionDecl> for ast::TyBareFn {
- fn clean(&self) -> BareFunctionDecl {
- BareFunctionDecl {
- purity: self.purity,
- generics: Generics {
- lifetimes: self.lifetimes.clean(),
- type_params: ~[],
- },
- decl: self.decl.clean(),
- abi: self.abis.to_str(),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Static {
- type_: Type,
- mutability: Mutability,
- /// It's useful to have the value of a static documented, but I have no
- /// desire to represent expressions (that'd basically be all of the AST,
- /// which is huge!). So, have a string.
- expr: ~str,
-}
-
-impl Clean<Item> for doctree::Static {
- fn clean(&self) -> Item {
- debug!("claning static %s: %?", self.name.clean(), self);
- Item {
- name: Some(self.name.clean()),
- attrs: self.attrs.clean(),
- source: self.where.clean(),
- id: self.id,
- visibility: self.vis.clean(),
- inner: StaticItem(Static {
- type_: self.type_.clean(),
- mutability: self.mutability.clean(),
- expr: self.expr.span.to_src(),
- }),
- }
- }
-}
-
-#[deriving(ToStr, Clone, Encodable, Decodable)]
-pub enum Mutability {
- Mutable,
- Immutable,
-}
-
-impl Clean<Mutability> for ast::Mutability {
- fn clean(&self) -> Mutability {
- match self {
- &ast::MutMutable => Mutable,
- &ast::MutImmutable => Immutable,
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct Impl {
- generics: Generics,
- trait_: Option<Type>,
- for_: Type,
- methods: ~[Item],
-}
-
-impl Clean<Item> for doctree::Impl {
- fn clean(&self) -> Item {
- Item {
- name: None,
- attrs: self.attrs.clean(),
- source: self.where.clean(),
- id: self.id,
- visibility: self.vis.clean(),
- inner: ImplItem(Impl {
- generics: self.generics.clean(),
- trait_: self.trait_.clean(),
- for_: self.for_.clean(),
- methods: self.methods.clean(),
- }),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub struct ViewItem {
- inner: ViewItemInner
-}
-
-impl Clean<Item> for ast::view_item {
- fn clean(&self) -> Item {
- Item {
- name: None,
- attrs: self.attrs.clean(),
- source: self.span.clean(),
- id: 0,
- visibility: self.vis.clean(),
- inner: ViewItemItem(ViewItem {
- inner: self.node.clean()
- }),
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub enum ViewItemInner {
- ExternMod(~str, Option<~str>, ~[Attribute], ast::NodeId),
- Import(~[ViewPath])
-}
-
-impl Clean<ViewItemInner> for ast::view_item_ {
- fn clean(&self) -> ViewItemInner {
- match self {
- &ast::view_item_extern_mod(ref i, ref p, ref mi, ref id) =>
- ExternMod(i.clean(), p.map(|x| x.to_owned()), mi.clean(), *id),
- &ast::view_item_use(ref vp) => Import(vp.clean())
- }
- }
-}
-
-#[deriving(Clone, Encodable, Decodable)]
-pub enum ViewPath {
- SimpleImport(~str, Path, ast::NodeId),
- GlobImport(Path, ast::NodeId),
- ImportList(Path, ~[ViewListIdent], ast::NodeId)
-}
-
-impl Clean<ViewPath> for ast::view_path {
- fn clean(&self) -> ViewPath {
- match self.node {
- ast::view_path_simple(ref i, ref p, ref id) => SimpleImport(i.clean(), p.clean(), *id),
- ast::view_path_glob(ref p, ref id) => GlobImport(p.clean(), *id),
- ast::view_path_list(ref p, ref pl, ref id) => ImportList(p.clean(), pl.clean(), *id),
- }
- }
-}
-
-pub type ViewListIdent = ~str;
-
-impl Clean<ViewListIdent> for ast::path_list_ident {
- fn clean(&self) -> ViewListIdent {
- self.node.name.clean()
- }
-}
-
-// Utilities
-
-trait ToSource {
- fn to_src(&self) -> ~str;
-}
-
-impl ToSource for syntax::codemap::Span {
- fn to_src(&self) -> ~str {
- debug!("converting span %s to snippet", self.clean());
- let cm = local_data::get(super::ctxtkey, |x| x.unwrap().clone()).sess.codemap.clone();
- let sn = match cm.span_to_snippet(*self) {
- Some(x) => x,
- None => ~""
- };
- debug!("got snippet %s", sn);
- sn
- }
-}
-
-fn lit_to_str(lit: &ast::lit) -> ~str {
- match lit.node {
- ast::lit_str(st) => st.to_owned(),
- ast::lit_char(c) => ~"'" + std::char::from_u32(c).unwrap().to_str() + "'",
- ast::lit_int(i, _t) => i.to_str(),
- ast::lit_uint(u, _t) => u.to_str(),
- ast::lit_int_unsuffixed(i) => i.to_str(),
- ast::lit_float(f, _t) => f.to_str(),
- ast::lit_float_unsuffixed(f) => f.to_str(),
- ast::lit_bool(b) => b.to_str(),
- ast::lit_nil => ~"",
- }
-}
-
-fn name_from_pat(p: &ast::Pat) -> ~str {
- use syntax::ast::*;
- match p.node {
- PatWild => ~"_",
- PatIdent(_, ref p, _) => path_to_str(p),
- PatEnum(ref p, _) => path_to_str(p),
- PatStruct(*) => fail!("tried to get argument name from pat_struct, \
- which is not allowed in function arguments"),
- PatTup(*) => ~"(tuple arg NYI)",
- PatBox(p) => name_from_pat(p),
- PatUniq(p) => name_from_pat(p),
- PatRegion(p) => name_from_pat(p),
- PatLit(*) => fail!("tried to get argument name from pat_lit, \
- which is not allowed in function arguments"),
- PatRange(*) => fail!("tried to get argument name from pat_range, \
- which is not allowed in function arguments"),
- PatVec(*) => fail!("tried to get argument name from pat_vec, \
- which is not allowed in function arguments")
- }
-}
-
-fn remove_comment_tags(s: &str) -> ~str {
- if s.starts_with("/") {
- match s.slice(0,3) {
- &"///" => return s.slice(3, s.len()).trim().to_owned(),
- &"/**" | &"/*!" => return s.slice(3, s.len() - 2).trim().to_owned(),
- _ => return s.trim().to_owned()
- }
- } else {
- return s.to_owned();
- }
-}
-
-/// Given a Type, resolve it using the def_map
-fn resolve_type(t: &Type) -> Type {
- use syntax::ast::*;
-
- let (path, tpbs, id) = match t {
- &Unresolved(ref path, ref tbps, id) => (path, tbps, id),
- _ => return (*t).clone(),
- };
-
- let dm = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.def_map;
- debug!("searching for %? in defmap", id);
- let d = match dm.find(&id) {
- Some(k) => k,
- None => {
- let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap());
- debug!("could not find %? in defmap (`%s`)", id,
- syntax::ast_map::node_id_to_str(ctxt.tycx.items, id, ctxt.sess.intr()));
- fail!("Unexpected failure: unresolved id not in defmap (this is a bug!)")
- }
- };
-
- let def_id = match *d {
- DefFn(i, _) => i,
- DefSelf(i) | DefSelfTy(i) => return Self(i),
- DefTy(i) => i,
- DefTrait(i) => {
- debug!("saw DefTrait in def_to_id");
- i
- },
- DefPrimTy(p) => match p {
- ty_str => return String,
- ty_bool => return Bool,
- _ => return Primitive(p)
- },
- DefTyParam(i, _) => return Generic(i.node),
- DefStruct(i) => i,
- DefTyParamBinder(i) => {
- debug!("found a typaram_binder, what is it? %d", i);
- return TyParamBinder(i);
- },
- x => fail!("resolved type maps to a weird def %?", x),
- };
-
- if def_id.crate != ast::CRATE_NODE_ID {
- use rustc::metadata::decoder::*;
-
- let sess = local_data::get(super::ctxtkey, |x| *x.unwrap()).sess;
- let cratedata = ::rustc::metadata::cstore::get_crate_data(sess.cstore, def_id.crate);
- let doc = lookup_item(def_id.node, cratedata.data);
- let path = syntax::ast_map::path_to_str_with_sep(item_path(doc), "::", sess.intr());
- let ty = match def_like_to_def(item_to_def_like(doc, def_id, def_id.crate)) {
- DefFn(*) => ~"fn",
- DefTy(*) => ~"enum",
- DefTrait(*) => ~"trait",
- DefPrimTy(p) => match p {
- ty_str => ~"str",
- ty_bool => ~"bool",
- ty_int(t) => match t.to_str() {
- ~"" => ~"i",
- s => s
- },
- ty_uint(t) => t.to_str(),
- ty_float(t) => t.to_str(),
- ty_char => ~"char",
- },
- DefTyParam(*) => ~"generic",
- DefStruct(*) => ~"struct",
- DefTyParamBinder(*) => ~"typaram_binder",
- x => fail!("resolved external maps to a weird def %?", x),
- };
- let cname = cratedata.name.to_owned();
- External(cname + "::" + path, ty)
- } else {
- ResolvedPath {path: path.clone(), typarams: tpbs.clone(), id: def_id.node}
- }
-}
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use rustc;
-use rustc::{driver, middle};
-
-use syntax;
-use syntax::parse;
-use syntax::ast;
-
-use std::os;
-use std::local_data;
-
-use visit_ast::RustdocVisitor;
-use clean;
-use clean::Clean;
-
-pub struct DocContext {
- crate: @ast::Crate,
- tycx: middle::ty::ctxt,
- sess: driver::session::Session
-}
-
-/// Parses, resolves, and typechecks the given crate
-fn get_ast_and_resolve(cpath: &Path, libs: ~[Path]) -> DocContext {
- use syntax::codemap::dummy_spanned;
- use rustc::driver::driver::*;
-
- let parsesess = parse::new_parse_sess(None);
- let input = file_input(cpath.clone());
-
- let sessopts = @driver::session::options {
- binary: @"rustdoc",
- maybe_sysroot: Some(@os::self_exe_path().unwrap().pop()),
- addl_lib_search_paths: @mut libs,
- .. (*rustc::driver::session::basic_options()).clone()
- };
-
-
- let diagnostic_handler = syntax::diagnostic::mk_handler(None);
- let span_diagnostic_handler =
- syntax::diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);
-
- let sess = driver::driver::build_session_(sessopts, parsesess.cm,
- syntax::diagnostic::emit,
- span_diagnostic_handler);
-
- let mut cfg = build_configuration(sess);
- cfg.push(@dummy_spanned(ast::MetaWord(@"stage2")));
-
- let mut crate = phase_1_parse_input(sess, cfg.clone(), &input);
- crate = phase_2_configure_and_expand(sess, cfg, crate);
- let analysis = phase_3_run_analysis_passes(sess, crate);
-
- debug!("crate: %?", crate);
- DocContext { crate: crate, tycx: analysis.ty_cx, sess: sess }
-}
-
-pub fn run_core (libs: ~[Path], path: &Path) -> clean::Crate {
- let ctxt = @get_ast_and_resolve(path, libs);
- debug!("defmap:");
- for (k, v) in ctxt.tycx.def_map.iter() {
- debug!("%?: %?", k, v);
- }
- local_data::set(super::ctxtkey, ctxt);
-
- let v = @mut RustdocVisitor::new();
- v.visit(ctxt.crate);
-
- v.clean()
-}
+++ /dev/null
-// Copyright 2012-2013 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.
-
-//! This module is used to store stuff from Rust's AST in a more convenient
-//! manner (and with prettier names) before cleaning.
-
-use syntax;
-use syntax::codemap::Span;
-use syntax::ast;
-use syntax::ast::{Ident, NodeId};
-
-pub struct Module {
- name: Option<Ident>,
- attrs: ~[ast::Attribute],
- where: Span,
- structs: ~[Struct],
- enums: ~[Enum],
- fns: ~[Function],
- mods: ~[Module],
- id: NodeId,
- typedefs: ~[Typedef],
- statics: ~[Static],
- traits: ~[Trait],
- vis: ast::visibility,
- impls: ~[Impl],
- view_items: ~[ast::view_item],
-}
-
-impl Module {
- pub fn new(name: Option<Ident>) -> Module {
- Module {
- name : name,
- id: 0,
- vis: ast::private,
- where: syntax::codemap::dummy_sp(),
- attrs : ~[],
- structs : ~[],
- enums : ~[],
- fns : ~[],
- mods : ~[],
- typedefs : ~[],
- statics : ~[],
- traits : ~[],
- impls : ~[],
- view_items : ~[],
- }
- }
-}
-
-#[deriving(ToStr, Clone, Encodable, Decodable)]
-pub enum StructType {
- /// A normal struct
- Plain,
- /// A tuple struct
- Tuple,
- /// A newtype struct (tuple struct with one element)
- Newtype,
- /// A unit struct
- Unit
-}
-
-pub enum TypeBound {
- RegionBound,
- TraitBound(ast::trait_ref)
-}
-
-pub struct Struct {
- vis: ast::visibility,
- id: NodeId,
- struct_type: StructType,
- name: Ident,
- generics: ast::Generics,
- attrs: ~[ast::Attribute],
- fields: ~[@ast::struct_field],
- where: Span,
-}
-
-pub struct Enum {
- vis: ast::visibility,
- variants: ~[Variant],
- generics: ast::Generics,
- attrs: ~[ast::Attribute],
- id: NodeId,
- where: Span,
- name: Ident,
-}
-
-pub struct Variant {
- name: Ident,
- attrs: ~[ast::Attribute],
- kind: ast::variant_kind,
- id: ast::NodeId,
- vis: ast::visibility,
- where: Span,
-}
-
-pub struct Function {
- decl: ast::fn_decl,
- attrs: ~[ast::Attribute],
- id: NodeId,
- name: Ident,
- vis: ast::visibility,
- where: Span,
- generics: ast::Generics,
-}
-
-pub struct Typedef {
- ty: ast::Ty,
- gen: ast::Generics,
- name: Ident,
- id: ast::NodeId,
- attrs: ~[ast::Attribute],
- where: Span,
- vis: ast::visibility,
-}
-
-pub struct Static {
- type_: ast::Ty,
- mutability: ast::Mutability,
- expr: @ast::Expr,
- name: Ident,
- attrs: ~[ast::Attribute],
- vis: ast::visibility,
- id: ast::NodeId,
- where: Span,
-}
-
-pub struct Trait {
- name: Ident,
- methods: ~[ast::trait_method], //should be TraitMethod
- generics: ast::Generics,
- parents: ~[ast::trait_ref],
- attrs: ~[ast::Attribute],
- id: ast::NodeId,
- where: Span,
- vis: ast::visibility,
-}
-
-pub struct Impl {
- generics: ast::Generics,
- trait_: Option<ast::trait_ref>,
- for_: ast::Ty,
- methods: ~[@ast::method],
- attrs: ~[ast::Attribute],
- where: Span,
- vis: ast::visibility,
- id: ast::NodeId,
-}
-
-pub fn struct_type_from_def(sd: &ast::struct_def) -> StructType {
- if sd.ctor_id.is_some() {
- // We are in a tuple-struct
- match sd.fields.len() {
- 0 => Unit,
- 1 => Newtype,
- _ => Tuple
- }
- } else {
- Plain
- }
-}
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std;
-use clean::*;
-use std::iter::Extendable;
-
-pub trait DocFolder {
- fn fold_item(&mut self, item: Item) -> Option<Item> {
- self.fold_item_recur(item)
- }
-
- /// don't override!
- fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
- use std::util::swap;
- let Item { attrs, name, source, visibility, id, inner } = item;
- let inner = inner;
- let c = |x| self.fold_item(x);
- let inner = match inner {
- StructItem(i) => {
- let mut i = i;
- let mut foo = ~[]; swap(&mut foo, &mut i.fields);
- i.fields.extend(&mut foo.move_iter().filter_map(|x| self.fold_item(x)));
- StructItem(i)
- },
- ModuleItem(i) => {
- ModuleItem(self.fold_mod(i))
- },
- EnumItem(i) => {
- let mut i = i;
- let mut foo = ~[]; swap(&mut foo, &mut i.variants);
- i.variants.extend(&mut foo.move_iter().filter_map(|x| self.fold_item(x)));
- EnumItem(i)
- },
- TraitItem(i) => {
- fn vtrm<T: DocFolder>(this: &mut T, trm: TraitMethod) -> Option<TraitMethod> {
- match trm {
- Required(it) => {
- match this.fold_item(it) {
- Some(x) => return Some(Required(x)),
- None => return None,
- }
- },
- Provided(it) => {
- match this.fold_item(it) {
- Some(x) => return Some(Provided(x)),
- None => return None,
- }
- },
- }
- }
- let mut i = i;
- let mut foo = ~[]; swap(&mut foo, &mut i.methods);
- i.methods.extend(&mut foo.move_iter().filter_map(|x| vtrm(self, x)));
- TraitItem(i)
- },
- ImplItem(i) => {
- let mut i = i;
- let mut foo = ~[]; swap(&mut foo, &mut i.methods);
- i.methods.extend(&mut foo.move_iter().filter_map(|x| self.fold_item(x)));
- ImplItem(i)
- },
- VariantItem(i) => {
- let i2 = i.clone(); // this clone is small
- match i.kind {
- StructVariant(j) => {
- let mut j = j;
- let mut foo = ~[]; swap(&mut foo, &mut j.fields);
- j.fields.extend(&mut foo.move_iter().filter_map(c));
- VariantItem(Variant {kind: StructVariant(j), ..i2})
- },
- _ => VariantItem(i2)
- }
- },
- x => x
- };
-
- Some(Item { attrs: attrs, name: name, source: source, inner: inner,
- visibility: visibility, id: id })
- }
-
- fn fold_mod(&mut self, m: Module) -> Module {
- Module { items: m.items.move_iter().filter_map(|i| self.fold_item(i)).collect() }
- }
-
- fn fold_crate(&mut self, mut c: Crate) -> Crate {
- c.module = match std::util::replace(&mut c.module, None) {
- Some(module) => self.fold_item(module), None => None
- };
- return c;
- }
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::fmt;
-use std::local_data;
-use std::rt::io;
-
-use syntax::ast;
-
-use clean;
-use html::render::{cache_key, current_location_key};
-
-pub struct VisSpace(Option<ast::visibility>);
-pub struct Method<'self>(&'self clean::SelfTy, &'self clean::FnDecl);
-
-impl fmt::Default for clean::Generics {
- fn fmt(g: &clean::Generics, f: &mut fmt::Formatter) {
- if g.lifetimes.len() == 0 && g.type_params.len() == 0 { return }
- f.buf.write("<".as_bytes());
-
- for (i, life) in g.lifetimes.iter().enumerate() {
- if i > 0 { f.buf.write(", ".as_bytes()); }
- write!(f.buf, "{}", *life);
- }
-
- if g.type_params.len() > 0 {
- if g.lifetimes.len() > 0 { f.buf.write(", ".as_bytes()); }
-
- for (i, tp) in g.type_params.iter().enumerate() {
- if i > 0 { f.buf.write(", ".as_bytes()) }
- f.buf.write(tp.name.as_bytes());
-
- if tp.bounds.len() > 0 {
- f.buf.write(": ".as_bytes());
- for (i, bound) in tp.bounds.iter().enumerate() {
- if i > 0 { f.buf.write(" + ".as_bytes()); }
- write!(f.buf, "{}", *bound);
- }
- }
- }
- }
- f.buf.write(">".as_bytes());
- }
-}
-
-impl fmt::Default for clean::Lifetime {
- fn fmt(l: &clean::Lifetime, f: &mut fmt::Formatter) {
- f.buf.write("'".as_bytes());
- f.buf.write(l.as_bytes());
- }
-}
-
-impl fmt::Default for clean::TyParamBound {
- fn fmt(bound: &clean::TyParamBound, f: &mut fmt::Formatter) {
- match *bound {
- clean::RegionBound => {
- f.buf.write("'static".as_bytes())
- }
- clean::TraitBound(ref ty) => {
- write!(f.buf, "{}", *ty);
- }
- }
- }
-}
-
-impl fmt::Default for clean::Path {
- fn fmt(path: &clean::Path, f: &mut fmt::Formatter) {
- if path.global { f.buf.write("::".as_bytes()) }
- for (i, seg) in path.segments.iter().enumerate() {
- if i > 0 { f.buf.write("::".as_bytes()) }
- f.buf.write(seg.name.as_bytes());
-
- if seg.lifetime.is_some() || seg.types.len() > 0 {
- f.buf.write("<".as_bytes());
- match seg.lifetime {
- Some(ref lifetime) => write!(f.buf, "{}", *lifetime),
- None => {}
- }
- for (i, ty) in seg.types.iter().enumerate() {
- if i > 0 || seg.lifetime.is_some() {
- f.buf.write(", ".as_bytes());
- }
- write!(f.buf, "{}", *ty);
- }
- f.buf.write(">".as_bytes());
- }
- }
- }
-}
-
-fn resolved_path(w: &mut io::Writer, id: ast::NodeId, path: &clean::Path) {
- // The generics will get written to both the title and link
- let mut generics = ~"";
- let last = path.segments.last();
- if last.lifetime.is_some() || last.types.len() > 0 {
- generics.push_str("<");
- match last.lifetime {
- Some(ref lifetime) => generics.push_str(format!("{}", *lifetime)),
- None => {}
- }
- for (i, ty) in last.types.iter().enumerate() {
- if i > 0 || last.lifetime.is_some() {
- generics.push_str(", ");
- }
- generics.push_str(format!("{}", *ty));
- }
- generics.push_str(">");
- }
-
- // Did someone say rightward-drift?
- do local_data::get(current_location_key) |loc| {
- let loc = loc.unwrap();
- do local_data::get(cache_key) |cache| {
- do cache.unwrap().read |cache| {
- match cache.paths.find(&id) {
- // This is a documented path, link to it!
- Some(&(ref fqp, shortty)) => {
- let fqn = fqp.connect("::");
- let mut same = 0;
- for (a, b) in loc.iter().zip(fqp.iter()) {
- if *a == *b {
- same += 1;
- } else {
- break;
- }
- }
-
- let mut url = ~"";
- for _ in range(same, loc.len()) {
- url.push_str("../");
- }
- if same == fqp.len() {
- url.push_str(shortty);
- url.push_str(".");
- url.push_str(*fqp.last());
- url.push_str(".html");
- } else {
- let remaining = fqp.slice_from(same);
- let to_link = remaining.slice_to(remaining.len() - 1);
- for component in to_link.iter() {
- url.push_str(*component);
- url.push_str("/");
- }
- url.push_str(shortty);
- url.push_str(".");
- url.push_str(*remaining.last());
- url.push_str(".html");
- }
-
- write!(w, "<a class='{}' href='{}' title='{}'>{}</a>{}",
- shortty, url, fqn, last.name, generics);
- }
- None => {
- write!(w, "{}{}", last.name, generics);
- }
- };
- }
- }
- }
-}
-
-impl fmt::Default for clean::Type {
- fn fmt(g: &clean::Type, f: &mut fmt::Formatter) {
- match *g {
- clean::TyParamBinder(id) | clean::Generic(id) => {
- do local_data::get(cache_key) |cache| {
- do cache.unwrap().read |m| {
- f.buf.write(m.typarams.get(&id).as_bytes());
- }
- }
- }
- clean::Unresolved(*) => unreachable!(),
- clean::ResolvedPath{id, typarams: ref typarams, path: ref path} => {
- resolved_path(f.buf, id, path);
- match *typarams {
- Some(ref params) => {
- f.buf.write("<".as_bytes());
- for (i, param) in params.iter().enumerate() {
- if i > 0 { f.buf.write(", ".as_bytes()) }
- write!(f.buf, "{}", *param);
- }
- f.buf.write(">".as_bytes());
- }
- None => {}
- }
- }
- // XXX: this should be a link
- clean::External(ref a, _) => {
- write!(f.buf, "{}", *a);
- }
- clean::Self(*) => f.buf.write("Self".as_bytes()),
- clean::Primitive(prim) => {
- let s = match prim {
- ast::ty_int(ast::ty_i) => "int",
- ast::ty_int(ast::ty_i8) => "i8",
- ast::ty_int(ast::ty_i16) => "i16",
- ast::ty_int(ast::ty_i32) => "i32",
- ast::ty_int(ast::ty_i64) => "i64",
- ast::ty_uint(ast::ty_u) => "uint",
- ast::ty_uint(ast::ty_u8) => "u8",
- ast::ty_uint(ast::ty_u16) => "u16",
- ast::ty_uint(ast::ty_u32) => "u32",
- ast::ty_uint(ast::ty_u64) => "u64",
- ast::ty_float(ast::ty_f) => "float",
- ast::ty_float(ast::ty_f32) => "f32",
- ast::ty_float(ast::ty_f64) => "f64",
- ast::ty_str => "str",
- ast::ty_bool => "bool",
- ast::ty_char => "char",
- };
- f.buf.write(s.as_bytes());
- }
- clean::Closure(ref decl) => {
- f.buf.write(match decl.sigil {
- ast::BorrowedSigil => "&",
- ast::ManagedSigil => "@",
- ast::OwnedSigil => "~",
- }.as_bytes());
- match decl.region {
- Some(ref region) => write!(f.buf, "{} ", *region),
- None => {}
- }
- write!(f.buf, "{}{}fn{}",
- match decl.purity {
- ast::unsafe_fn => "unsafe ",
- ast::extern_fn => "extern ",
- ast::impure_fn => ""
- },
- match decl.onceness {
- ast::Once => "once ",
- ast::Many => "",
- },
- decl.decl);
- // XXX: where are bounds and lifetimes printed?!
- }
- clean::BareFunction(ref decl) => {
- write!(f.buf, "{}{}fn{}{}",
- match decl.purity {
- ast::unsafe_fn => "unsafe ",
- ast::extern_fn => "extern ",
- ast::impure_fn => ""
- },
- match decl.abi {
- ~"" | ~"\"Rust\"" => ~"",
- ref s => " " + *s + " ",
- },
- decl.generics,
- decl.decl);
- }
- clean::Tuple(ref typs) => {
- f.buf.write("(".as_bytes());
- for (i, typ) in typs.iter().enumerate() {
- if i > 0 { f.buf.write(", ".as_bytes()) }
- write!(f.buf, "{}", *typ);
- }
- f.buf.write(")".as_bytes());
- }
- clean::Vector(ref t) => write!(f.buf, "[{}]", **t),
- clean::FixedVector(ref t, ref s) => {
- write!(f.buf, "[{}, ..{}]", **t, *s);
- }
- clean::String => f.buf.write("str".as_bytes()),
- clean::Bool => f.buf.write("bool".as_bytes()),
- clean::Unit => f.buf.write("()".as_bytes()),
- clean::Bottom => f.buf.write("!".as_bytes()),
- clean::Unique(ref t) => write!(f.buf, "~{}", **t),
- clean::Managed(m, ref t) => {
- write!(f.buf, "@{}{}",
- match m {
- clean::Mutable => "mut ",
- clean::Immutable => "",
- }, **t)
- }
- clean::RawPointer(m, ref t) => {
- write!(f.buf, "*{}{}",
- match m {
- clean::Mutable => "mut ",
- clean::Immutable => "",
- }, **t)
- }
- clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
- let lt = match *l { Some(ref l) => format!("{} ", *l), _ => ~"" };
- write!(f.buf, "&{}{}{}",
- lt,
- match mutability {
- clean::Mutable => "mut ",
- clean::Immutable => "",
- },
- **ty);
- }
- }
- }
-}
-
-impl fmt::Default for clean::FnDecl {
- fn fmt(d: &clean::FnDecl, f: &mut fmt::Formatter) {
- let mut args = ~"";
- for (i, input) in d.inputs.iter().enumerate() {
- if i > 0 { args.push_str(", "); }
- if input.name.len() > 0 {
- args.push_str(format!("{}: ", input.name));
- }
- args.push_str(format!("{}", input.type_));
- }
- write!(f.buf, "({args}){arrow, select, yes{ -> {ret}} other{}}",
- args = args,
- arrow = match d.output { clean::Unit => "no", _ => "yes" },
- ret = d.output);
- }
-}
-
-impl<'self> fmt::Default for Method<'self> {
- fn fmt(m: &Method<'self>, f: &mut fmt::Formatter) {
- let Method(selfty, d) = *m;
- let mut args = ~"";
- match *selfty {
- clean::SelfStatic => {},
- clean::SelfValue => args.push_str("self"),
- clean::SelfOwned => args.push_str("~self"),
- clean::SelfManaged(clean::Mutable) => args.push_str("@mut self"),
- clean::SelfManaged(clean::Immutable) => args.push_str("@self"),
- clean::SelfBorrowed(Some(ref lt), clean::Immutable) => {
- args.push_str(format!("&{} self", *lt));
- }
- clean::SelfBorrowed(Some(ref lt), clean::Mutable) => {
- args.push_str(format!("&{} mut self", *lt));
- }
- clean::SelfBorrowed(None, clean::Mutable) => {
- args.push_str("&mut self");
- }
- clean::SelfBorrowed(None, clean::Immutable) => {
- args.push_str("&self");
- }
- }
- for (i, input) in d.inputs.iter().enumerate() {
- if i > 0 || args.len() > 0 { args.push_str(", "); }
- if input.name.len() > 0 {
- args.push_str(format!("{}: ", input.name));
- }
- args.push_str(format!("{}", input.type_));
- }
- write!(f.buf, "({args}){arrow, select, yes{ -> {ret}} other{}}",
- args = args,
- arrow = match d.output { clean::Unit => "no", _ => "yes" },
- ret = d.output);
- }
-}
-
-impl fmt::Default for VisSpace {
- fn fmt(v: &VisSpace, f: &mut fmt::Formatter) {
- match **v {
- Some(ast::public) => { write!(f.buf, "pub "); }
- Some(ast::private) => { write!(f.buf, "priv "); }
- Some(ast::inherited) | None => {}
- }
- }
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::fmt;
-use std::rt::io;
-
-#[deriving(Clone)]
-pub struct Layout {
- logo: ~str,
- favicon: ~str,
- crate: ~str,
-}
-
-pub struct Page<'self> {
- title: &'self str,
- ty: &'self str,
- root_path: &'self str,
-}
-
-pub fn render<T: fmt::Default, S: fmt::Default>(
- dst: &mut io::Writer, layout: &Layout, page: &Page, sidebar: &S, t: &T)
-{
- write!(dst, "
-<!DOCTYPE html>
-<html lang=\"en\">
-<head>
- <meta charset=\"utf-8\" />
- <title>{title}</title>
-
- <link href='http://fonts.googleapis.com/css?family=Oswald:700|Inconsolata:400'
- rel='stylesheet' type='text/css'>
- <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}main.css\">
-
- {favicon, select, none{} other{
- <link rel=\"icon\" href=\"#\" sizes=\"16x16\"
- type=\"image/vnd.microsoft.icon\" />}}
-</head>
-<body>
- <!--[if lte IE 8]>
- <div class=\"warning\">
- This old browser is unsupported and will most likely display funky
- things
- </div>
- <![endif]-->
-
- <section class=\"sidebar\">
- {logo, select, none{} other{
- <a href='{root_path}index.html'><img src='#' alt=''/></a>
- }}
-
- {sidebar}
- </section>
-
- <nav class=\"sub\">
- <form class=\"search-form js-only\">
- <input class=\"search-input\" name=\"search\"
- autocomplete=\"off\" />
- <button class=\"do-search\">Search</button>
- </form>
- </nav>
-
- <section class=\"content {ty}\">{content}</section>
-
- <section class=\"footer\"></section>
-
- <script>
- var rootPath = \"{root_path}\";
- </script>
- <script src=\"{root_path}jquery.js\"></script>
- <script src=\"{root_path}{crate}/search-index.js\"></script>
- <script src=\"{root_path}main.js\"></script>
-
- <div id=\"help\" class=\"hidden\">
- <div class=\"shortcuts\">
- <h1>Keyboard shortcuts</h1>
- <dl>
- <dt>?</dt>
- <dd>Show this help dialog</dd>
- <dt>S</dt>
- <dd>Focus the search field</dd>
- <dt>↑</dt>
- <dd>Move up in search results</dd>
- <dt>↓</dt>
- <dd>Move down in search results</dd>
- <dt>&\\#9166;</dt>
- <dd>Go to active search result</dd>
- </dl>
- </div>
- <div class=\"infos\">
- <h1>Search tricks</h1>
- <p>
- Prefix searches with a type followed by a colon (e.g.
- <code>fn:</code>) to restrict the search to a given type.
- </p>
- <p>
- Accepted types are: <code>fn</code>, <code>mod</code>,
- <code>struct</code> (or <code>str</code>), <code>enum</code>,
- <code>trait</code>, <code>typedef</code> (or
- <code>tdef</code>).
- </p>
- </div>
- </div>
-</body>
-</html>
-",
- content = *t,
- root_path = page.root_path,
- ty = page.ty,
- logo = nonestr(layout.logo),
- title = page.title,
- favicon = nonestr(layout.favicon),
- sidebar = *sidebar,
- crate = layout.crate,
- );
-}
-
-fn boolstr(b: bool) -> &'static str {
- if b { "true" } else { "false" }
-}
-
-fn nonestr<'a>(s: &'a str) -> &'a str {
- if s == "" { "none" } else { s }
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::fmt;
-use std::rt::io::Reader;
-use std::rt::io::pipe::PipeStream;
-use std::rt::io::process::{ProcessConfig, Process, CreatePipe};
-use std::rt::io;
-
-pub struct Markdown<'self>(&'self str);
-
-impl<'self> fmt::Default for Markdown<'self> {
- fn fmt(md: &Markdown<'self>, fmt: &mut fmt::Formatter) {
- if md.len() == 0 { return; }
-
- // Create the pandoc process
- do io::io_error::cond.trap(|err| {
- fail2!("Error executing `pandoc`: {}", err.desc);
- }).inside {
- let io = ~[CreatePipe(PipeStream::new().unwrap(), true, false),
- CreatePipe(PipeStream::new().unwrap(), false, true)];
- let args = ProcessConfig {
- program: "pandoc",
- args: [],
- env: None,
- cwd: None,
- io: io,
- };
- let mut p = Process::new(args).expect("couldn't fork for pandoc");
-
- // Write the markdown to stdin and close it.
- p.io[0].get_mut_ref().write(md.as_bytes());
- p.io[0] = None;
-
- // Ferry the output from pandoc over to the destination buffer.
- let mut buf = [0, ..1024];
- loop {
- match p.io[1].get_mut_ref().read(buf) {
- None | Some(0) => { break }
- Some(n) => {
- fmt.buf.write(buf.slice_to(n));
- }
- }
- }
- }
- }
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::cell::Cell;
-use std::comm::{SharedPort, SharedChan};
-use std::comm;
-use std::fmt;
-use std::hashmap::HashMap;
-use std::local_data;
-use std::rt::io::buffered::BufferedWriter;
-use std::rt::io::file::{FileInfo, DirectoryInfo};
-use std::rt::io::file;
-use std::rt::io;
-use std::task;
-use std::unstable::finally::Finally;
-use std::util;
-use std::vec;
-
-use extra::arc::RWArc;
-use extra::json::ToJson;
-use extra::sort;
-
-use syntax::ast;
-
-use clean;
-use doctree;
-use fold::DocFolder;
-use html::format::{VisSpace, Method};
-use html::layout;
-use html::markdown::Markdown;
-
-#[deriving(Clone)]
-pub struct Context {
- current: ~[~str],
- root_path: ~str,
- dst: Path,
- layout: layout::Layout,
- sidebar: HashMap<~str, ~[~str]>,
-}
-
-enum Implementor {
- PathType(clean::Type),
- OtherType(clean::Generics, /* trait */ clean::Type, /* for */ clean::Type),
-}
-
-struct Cache {
- // typaram id => name of that typaram
- typarams: HashMap<ast::NodeId, ~str>,
- // type id => all implementations for that type
- impls: HashMap<ast::NodeId, ~[clean::Impl]>,
- // path id => (full qualified path, shortty) -- used to generate urls
- paths: HashMap<ast::NodeId, (~[~str], &'static str)>,
- // trait id => method name => dox
- traits: HashMap<ast::NodeId, HashMap<~str, ~str>>,
- // trait id => implementors of the trait
- implementors: HashMap<ast::NodeId, ~[Implementor]>,
-
- priv stack: ~[~str],
- priv parent_stack: ~[ast::NodeId],
- priv search_index: ~[IndexItem],
-}
-
-struct Item<'self> { cx: &'self Context, item: &'self clean::Item, }
-struct Sidebar<'self> { cx: &'self Context, item: &'self clean::Item, }
-
-struct IndexItem {
- ty: &'static str,
- name: ~str,
- path: ~str,
- desc: ~str,
- parent: Option<ast::NodeId>,
-}
-
-local_data_key!(pub cache_key: RWArc<Cache>)
-local_data_key!(pub current_location_key: ~[~str])
-
-/// Generates the documentation for `crate` into the directory `dst`
-pub fn run(mut crate: clean::Crate, dst: Path) {
- let mut cx = Context {
- dst: dst,
- current: ~[],
- root_path: ~"",
- sidebar: HashMap::new(),
- layout: layout::Layout {
- logo: ~"",
- favicon: ~"",
- crate: crate.name.clone(),
- },
- };
- mkdir(&cx.dst);
-
- match crate.module.get_ref().doc_list() {
- Some(attrs) => {
- for attr in attrs.iter() {
- match *attr {
- clean::NameValue(~"html_favicon_url", ref s) => {
- cx.layout.favicon = s.to_owned();
- }
- clean::NameValue(~"html_logo_url", ref s) => {
- cx.layout.logo = s.to_owned();
- }
- _ => {}
- }
- }
- }
- None => {}
- }
-
- // Crawl the crate to build various caches used for the output
- let mut cache = Cache {
- impls: HashMap::new(),
- typarams: HashMap::new(),
- paths: HashMap::new(),
- traits: HashMap::new(),
- implementors: HashMap::new(),
- stack: ~[],
- parent_stack: ~[],
- search_index: ~[],
- };
- cache.stack.push(crate.name.clone());
- crate = cache.fold_crate(crate);
-
- // Add all the static files
- write(cx.dst.push("jquery.js"), include_str!("static/jquery-2.0.3.min.js"));
- write(cx.dst.push("main.js"), include_str!("static/main.js"));
- write(cx.dst.push("main.css"), include_str!("static/main.css"));
- write(cx.dst.push("normalize.css"), include_str!("static/normalize.css"));
- write(cx.dst.push("index.html"), format!("
- <DOCTYPE html><html><head>
- <meta http-equiv='refresh'
- content=\"0; url={}/index.html\">
- </head><body></body></html>
- ", crate.name));
-
- {
- mkdir(&cx.dst.push(crate.name));
- let dst = cx.dst.push(crate.name).push("search-index.js");
- let mut w = BufferedWriter::new(dst.open_writer(io::CreateOrTruncate));
- let w = &mut w as &mut io::Writer;
- write!(w, "var searchIndex = [");
- for (i, item) in cache.search_index.iter().enumerate() {
- if i > 0 { write!(w, ","); }
- write!(w, "\\{ty:\"{}\",name:\"{}\",path:\"{}\",desc:{}",
- item.ty, item.name, item.path,
- item.desc.to_json().to_str())
- match item.parent {
- Some(id) => { write!(w, ",parent:'{}'", id); }
- None => {}
- }
- write!(w, "\\}");
- }
- write!(w, "];");
- write!(w, "var allPaths = \\{");
- for (i, (&id, &(ref fqp, short))) in cache.paths.iter().enumerate() {
- if i > 0 { write!(w, ","); }
- write!(w, "'{}':\\{type:'{}',name:'{}'\\}", id, short, *fqp.last());
- }
- write!(w, "\\};");
- w.flush();
- }
-
- // Now render the whole crate.
- cx.crate(crate, cache);
-}
-
-fn write(dst: Path, contents: &str) {
- let mut w = dst.open_writer(io::CreateOrTruncate);
- w.write(contents.as_bytes());
-}
-
-fn mkdir(path: &Path) {
- do io::io_error::cond.trap(|err| {
- error2!("Couldn't create directory `{}`: {}",
- path.to_str(), err.desc);
- fail!()
- }).inside {
- if !path.is_dir() {
- file::mkdir(path);
- }
- }
-}
-
-impl<'self> DocFolder for Cache {
- fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
- // Register any generics to their corresponding string. This is used
- // when pretty-printing types
- match item.inner {
- clean::StructItem(ref s) => self.generics(&s.generics),
- clean::EnumItem(ref e) => self.generics(&e.generics),
- clean::FunctionItem(ref f) => self.generics(&f.generics),
- clean::TypedefItem(ref t) => self.generics(&t.generics),
- clean::TraitItem(ref t) => self.generics(&t.generics),
- clean::ImplItem(ref i) => self.generics(&i.generics),
- clean::TyMethodItem(ref i) => self.generics(&i.generics),
- clean::MethodItem(ref i) => self.generics(&i.generics),
- _ => {}
- }
-
- // Propagate a trait methods' documentation to all implementors of the
- // trait
- match item.inner {
- clean::TraitItem(ref t) => {
- let mut dox = HashMap::new();
- for meth in t.methods.iter() {
- let it = meth.item();
- match it.doc_value() {
- None => {}
- Some(s) => {
- dox.insert(it.name.get_ref().to_owned(),
- s.to_owned());
- }
- }
- }
- self.traits.insert(item.id, dox);
- }
- _ => {}
- }
-
- // Collect all the implementors of traits.
- match item.inner {
- clean::ImplItem(ref i) => {
- match i.trait_ {
- Some(clean::ResolvedPath{ id, _ }) => {
- let v = do self.implementors.find_or_insert_with(id) |_|{
- ~[]
- };
- match i.for_ {
- clean::ResolvedPath{_} => {
- v.unshift(PathType(i.for_.clone()));
- }
- _ => {
- v.push(OtherType(i.generics.clone(),
- i.trait_.get_ref().clone(),
- i.for_.clone()));
- }
- }
- }
- Some(*) | None => {}
- }
- }
- _ => {}
- }
-
- // Index this method for searching later on
- match item.name {
- Some(ref s) => {
- let parent = match item.inner {
- clean::TyMethodItem(*) | clean::VariantItem(*) => {
- Some((Some(*self.parent_stack.last()),
- self.stack.slice_to(self.stack.len() - 1)))
-
- }
- clean::MethodItem(*) => {
- if self.parent_stack.len() == 0 {
- None
- } else {
- Some((Some(*self.parent_stack.last()),
- self.stack.as_slice()))
- }
- }
- _ => Some((None, self.stack.as_slice()))
- };
- match parent {
- Some((parent, path)) => {
- self.search_index.push(IndexItem {
- ty: shortty(&item),
- name: s.to_owned(),
- path: path.connect("::"),
- desc: shorter(item.doc_value()).to_owned(),
- parent: parent,
- });
- }
- None => {}
- }
- }
- None => {}
- }
-
- // Keep track of the fully qualified path for this item.
- let pushed = if item.name.is_some() {
- let n = item.name.get_ref();
- if n.len() > 0 {
- self.stack.push(n.to_owned());
- true
- } else { false }
- } else { false };
- match item.inner {
- clean::StructItem(*) | clean::EnumItem(*) |
- clean::TypedefItem(*) | clean::TraitItem(*) => {
- self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
- }
- _ => {}
- }
-
- // Maintain the parent stack
- let parent_pushed = match item.inner {
- clean::TraitItem(*) | clean::EnumItem(*) => {
- self.parent_stack.push(item.id); true
- }
- clean::ImplItem(ref i) => {
- match i.for_ {
- clean::ResolvedPath{ id, _ } => {
- self.parent_stack.push(id); true
- }
- _ => false
- }
- }
- _ => false
- };
-
- // Once we've recursively found all the generics, then hoard off all the
- // implementations elsewhere
- let ret = match self.fold_item_recur(item) {
- Some(item) => {
- match item.inner {
- clean::ImplItem(i) => {
- match i.for_ {
- clean::ResolvedPath { id, _ } => {
- let v = do self.impls.find_or_insert_with(id) |_| {
- ~[]
- };
- v.push(i);
- }
- _ => {}
- }
- None
- }
- _ => Some(item),
- }
- }
- i => i,
- };
-
- if pushed { self.stack.pop(); }
- if parent_pushed { self.parent_stack.pop(); }
- return ret;
- }
-}
-
-impl<'self> Cache {
- fn generics(&mut self, generics: &clean::Generics) {
- for typ in generics.type_params.iter() {
- self.typarams.insert(typ.id, typ.name.clone());
- }
- }
-}
-
-impl Context {
- fn recurse<T>(&mut self, s: ~str, f: &fn(&mut Context) -> T) -> T {
- // Recurse in the directory structure and change the "root path" to make
- // sure it always points to the top (relatively)
- if s.len() == 0 {
- fail2!("what {:?}", self);
- }
- let next = self.dst.push(s);
- let prev = util::replace(&mut self.dst, next);
- self.root_path.push_str("../");
- self.current.push(s);
-
- mkdir(&self.dst);
- let ret = f(self);
-
- // Go back to where we were at
- self.dst = prev;
- let len = self.root_path.len();
- self.root_path.truncate(len - 3);
- self.current.pop();
-
- return ret;
- }
-
- /// Processes
- fn crate(self, mut crate: clean::Crate, cache: Cache) {
- enum Work {
- Die,
- Process(Context, clean::Item),
- }
- enum Progress { JobNew, JobDone }
- static WORKERS: int = 10;
-
- let mut item = match crate.module.take() {
- Some(i) => i,
- None => return
- };
- item.name = Some(crate.name);
-
- let (port, chan) = comm::stream::<Work>();
- let port = SharedPort::new(port);
- let chan = SharedChan::new(chan);
- let (prog_port, prog_chan) = comm::stream();
- let prog_chan = SharedChan::new(prog_chan);
- let cache = RWArc::new(cache);
-
- for i in range(0, WORKERS) {
- let port = port.clone();
- let chan = chan.clone();
- let prog_chan = prog_chan.clone();
-
- let mut task = task::task();
- task.unlinked(); // we kill things manually
- task.name(format!("worker{}", i));
- do task.spawn_with(cache.clone()) |cache| {
- local_data::set(cache_key, cache);
- loop {
- match port.recv() {
- Process(cx, item) => {
- let mut cx = cx;
- let item = Cell::new(item);
- do (|| {
- do cx.item(item.take()) |cx, item| {
- prog_chan.send(JobNew);
- chan.send(Process(cx.clone(), item));
- }
- }).finally {
- // If we fail, everything else should still get
- // completed
- prog_chan.send(JobDone);
- }
- }
- Die => break,
- }
- }
- }
- }
-
- let watcher_chan = chan.clone();
- let (done_port, done_chan) = comm::stream();
- do task::spawn {
- let mut jobs = 0;
- loop {
- match prog_port.recv() {
- JobNew => jobs += 1,
- JobDone => jobs -= 1,
- }
-
- if jobs == 0 { break }
- }
-
- for _ in range(0, WORKERS) {
- watcher_chan.send(Die);
- }
- done_chan.send(());
- }
-
- prog_chan.send(JobNew);
- chan.send(Process(self, item));
- done_port.recv();
- }
-
- fn item(&mut self, item: clean::Item, f: &fn(&mut Context, clean::Item)) {
- fn render(w: io::file::FileWriter, cx: &mut Context, it: &clean::Item,
- pushname: bool) {
- // A little unfortunate that this is done like this, but it sure
- // does make formatting *a lot* nicer.
- local_data::set(current_location_key, cx.current.clone());
-
- let mut title = cx.current.connect("::");
- if pushname {
- if title.len() > 0 { title.push_str("::"); }
- title.push_str(*it.name.get_ref());
- }
- title.push_str(" - Rust");
- let page = layout::Page {
- ty: shortty(it),
- root_path: cx.root_path,
- title: title,
- };
-
- // We have a huge number of calls to write, so try to alleviate some
- // of the pain by using a buffered writer instead of invoking the
- // write sycall all the time.
- let mut writer = BufferedWriter::new(w);
- layout::render(&mut writer as &mut io::Writer, &cx.layout, &page,
- &Sidebar{ cx: cx, item: it },
- &Item{ cx: cx, item: it });
- writer.flush();
- }
-
- match item.inner {
- clean::ModuleItem(*) => {
- let name = item.name.get_ref().to_owned();
- let item = Cell::new(item);
- do self.recurse(name) |this| {
- let item = item.take();
- let dst = this.dst.push("index.html");
- let writer = dst.open_writer(io::CreateOrTruncate);
- render(writer.unwrap(), this, &item, false);
-
- let m = match item.inner {
- clean::ModuleItem(m) => m,
- _ => unreachable!()
- };
- this.sidebar = build_sidebar(&m);
- for item in m.items.move_iter() {
- f(this, item);
- }
- }
- }
- _ if item.name.is_some() => {
- let dst = self.dst.push(item_path(&item));
- let writer = dst.open_writer(io::CreateOrTruncate);
- render(writer.unwrap(), self, &item, true);
- }
- _ => {}
- }
- }
-}
-
-fn shortty(item: &clean::Item) -> &'static str {
- match item.inner {
- clean::ModuleItem(*) => "mod",
- clean::StructItem(*) => "struct",
- clean::EnumItem(*) => "enum",
- clean::FunctionItem(*) => "fn",
- clean::TypedefItem(*) => "typedef",
- clean::StaticItem(*) => "static",
- clean::TraitItem(*) => "trait",
- clean::ImplItem(*) => "impl",
- clean::ViewItemItem(*) => "viewitem",
- clean::TyMethodItem(*) => "tymethod",
- clean::MethodItem(*) => "method",
- clean::StructFieldItem(*) => "structfield",
- clean::VariantItem(*) => "variant",
- }
-}
-
-impl<'self> Item<'self> {
- fn ismodule(&self) -> bool {
- match self.item.inner {
- clean::ModuleItem(*) => true, _ => false
- }
- }
-}
-
-impl<'self> fmt::Default for Item<'self> {
- fn fmt(it: &Item<'self>, fmt: &mut fmt::Formatter) {
- // Write the breadcrumb trail header for the top
- write!(fmt.buf, "<h1 class='fqn'>");
- match it.item.inner {
- clean::ModuleItem(*) => write!(fmt.buf, "Module "),
- clean::FunctionItem(*) => write!(fmt.buf, "Function "),
- clean::TraitItem(*) => write!(fmt.buf, "Trait "),
- clean::StructItem(*) => write!(fmt.buf, "Struct "),
- clean::EnumItem(*) => write!(fmt.buf, "Enum "),
- _ => {}
- }
- let cur = it.cx.current.as_slice();
- let amt = if it.ismodule() { cur.len() - 1 } else { cur.len() };
- for (i, component) in cur.iter().enumerate().take(amt) {
- let mut trail = ~"";
- for _ in range(0, cur.len() - i - 1) {
- trail.push_str("../");
- }
- write!(fmt.buf, "<a href='{}index.html'>{}</a>::",
- trail, component.as_slice());
- }
- write!(fmt.buf, "<a class='{}' href=''>{}</a></h1>",
- shortty(it.item), it.item.name.get_ref().as_slice());
-
- match it.item.inner {
- clean::ModuleItem(ref m) => item_module(fmt.buf, it.cx,
- it.item, m.items),
- clean::FunctionItem(ref f) => item_function(fmt.buf, it.item, f),
- clean::TraitItem(ref t) => item_trait(fmt.buf, it.item, t),
- clean::StructItem(ref s) => item_struct(fmt.buf, it.item, s),
- clean::EnumItem(ref e) => item_enum(fmt.buf, it.item, e),
- clean::TypedefItem(ref t) => item_typedef(fmt.buf, it.item, t),
- _ => {}
- }
- }
-}
-
-fn item_path(item: &clean::Item) -> ~str {
- match item.inner {
- clean::ModuleItem(*) => *item.name.get_ref() + "/index.html",
- _ => shortty(item) + "." + *item.name.get_ref() + ".html"
- }
-}
-
-fn full_path(cx: &Context, item: &clean::Item) -> ~str {
- let mut s = cx.current.connect("::");
- s.push_str("::");
- s.push_str(item.name.get_ref().as_slice());
- return s;
-}
-
-fn blank<'a>(s: Option<&'a str>) -> &'a str {
- match s {
- Some(s) => s,
- None => ""
- }
-}
-
-fn shorter<'a>(s: Option<&'a str>) -> &'a str {
- match s {
- Some(s) => match s.find_str("\n\n") {
- Some(pos) => s.slice_to(pos),
- None => s,
- },
- None => ""
- }
-}
-
-fn document(w: &mut io::Writer, item: &clean::Item) {
- match item.doc_value() {
- Some(s) => {
- write!(w, "<div class='docblock'>{}</div>", Markdown(s));
- }
- None => {}
- }
-}
-
-fn item_module(w: &mut io::Writer, cx: &Context,
- item: &clean::Item, items: &[clean::Item]) {
- document(w, item);
- let mut indices = vec::from_fn(items.len(), |i| i);
-
- fn lt(i1: &clean::Item, i2: &clean::Item) -> bool {
- if shortty(i1) == shortty(i2) {
- return i1.name < i2.name;
- }
- match (&i1.inner, &i2.inner) {
- (&clean::ViewItemItem(*), _) => true,
- (_, &clean::ViewItemItem(*)) => false,
- (&clean::ModuleItem(*), _) => true,
- (_, &clean::ModuleItem(*)) => false,
- (&clean::StructItem(*), _) => true,
- (_, &clean::StructItem(*)) => false,
- (&clean::EnumItem(*), _) => true,
- (_, &clean::EnumItem(*)) => false,
- (&clean::StaticItem(*), _) => true,
- (_, &clean::StaticItem(*)) => false,
- (&clean::TraitItem(*), _) => true,
- (_, &clean::TraitItem(*)) => false,
- (&clean::FunctionItem(*), _) => true,
- (_, &clean::FunctionItem(*)) => false,
- (&clean::TypedefItem(*), _) => true,
- (_, &clean::TypedefItem(*)) => false,
- _ => false,
- }
- }
-
- do sort::quick_sort(indices) |&i1, &i2| {
- lt(&items[i1], &items[i2])
- }
-
- let mut curty = "";
- for &idx in indices.iter() {
- let myitem = &items[idx];
- if myitem.name.is_none() { loop }
-
- let myty = shortty(myitem);
- if myty != curty {
- if curty != "" {
- write!(w, "</table>");
- }
- curty = myty;
- write!(w, "<h2>{}</h2>\n<table>", match myitem.inner {
- clean::ModuleItem(*) => "Modules",
- clean::StructItem(*) => "Structs",
- clean::EnumItem(*) => "Enums",
- clean::FunctionItem(*) => "Functions",
- clean::TypedefItem(*) => "Type Definitions",
- clean::StaticItem(*) => "Statics",
- clean::TraitItem(*) => "Traits",
- clean::ImplItem(*) => "Implementations",
- clean::ViewItemItem(*) => "Reexports",
- clean::TyMethodItem(*) => "Type Methods",
- clean::MethodItem(*) => "Methods",
- clean::StructFieldItem(*) => "Struct Fields",
- clean::VariantItem(*) => "Variants",
- });
- }
-
- match myitem.inner {
- clean::StaticItem(ref s) => {
- struct Initializer<'self>(&'self str);
- impl<'self> fmt::Default for Initializer<'self> {
- fn fmt(s: &Initializer<'self>, f: &mut fmt::Formatter) {
- let tag = if s.contains("\n") { "pre" } else { "code" };
- write!(f.buf, "<{tag}>{}</{tag}>",
- s.as_slice(), tag=tag);
- }
- }
-
- write!(w, "
- <tr>
- <td><code>{}: {} = </code>{}</td>
- <td class='docblock'>{} </td>
- </tr>
- ",
- *myitem.name.get_ref(),
- s.type_,
- Initializer(s.expr),
- Markdown(blank(myitem.doc_value())));
- }
-
- _ => {
- write!(w, "
- <tr>
- <td><a class='{class}' href='{href}'
- title='{title}'>{}</a></td>
- <td class='docblock short'>{}</td>
- </tr>
- ",
- *myitem.name.get_ref(),
- Markdown(shorter(myitem.doc_value())),
- class = shortty(myitem),
- href = item_path(myitem),
- title = full_path(cx, myitem));
- }
- }
- }
- write!(w, "</table>");
-}
-
-fn item_function(w: &mut io::Writer, it: &clean::Item, f: &clean::Function) {
- write!(w, "<pre class='fn'>{vis}fn {name}{generics}{decl}</pre>",
- vis = VisSpace(it.visibility),
- name = it.name.get_ref().as_slice(),
- generics = f.generics,
- decl = f.decl);
- document(w, it);
-}
-
-fn item_trait(w: &mut io::Writer, it: &clean::Item, t: &clean::Trait) {
- let mut parents = ~"";
- if t.parents.len() > 0 {
- parents.push_str(": ");
- for (i, p) in t.parents.iter().enumerate() {
- if i > 0 { parents.push_str(" + "); }
- parents.push_str(format!("{}", *p));
- }
- }
-
- // Output the trait definition
- write!(w, "<pre class='trait'>{}trait {}{}{} ",
- VisSpace(it.visibility),
- it.name.get_ref().as_slice(),
- t.generics,
- parents);
- let required = t.methods.iter().filter(|m| m.is_req()).to_owned_vec();
- let provided = t.methods.iter().filter(|m| !m.is_req()).to_owned_vec();
-
- if t.methods.len() == 0 {
- write!(w, "\\{ \\}");
- } else {
- write!(w, "\\{\n");
- for m in required.iter() {
- write!(w, " ");
- render_method(w, m.item(), true);
- write!(w, ";\n");
- }
- if required.len() > 0 && provided.len() > 0 {
- w.write("\n".as_bytes());
- }
- for m in provided.iter() {
- write!(w, " ");
- render_method(w, m.item(), true);
- write!(w, " \\{ ... \\}\n");
- }
- write!(w, "\\}");
- }
- write!(w, "</pre>");
-
- // Trait documentation
- document(w, it);
-
- fn meth(w: &mut io::Writer, m: &clean::TraitMethod) {
- write!(w, "<h3 id='fn.{}' class='method'><code>",
- *m.item().name.get_ref());
- render_method(w, m.item(), false);
- write!(w, "</code></h3>");
- document(w, m.item());
- }
-
- // Output the documentation for each function individually
- if required.len() > 0 {
- write!(w, "
- <h2 id='required-methods'>Required Methods</h2>
- <div class='methods'>
- ");
- for m in required.iter() {
- meth(w, *m);
- }
- write!(w, "</div>");
- }
- if provided.len() > 0 {
- write!(w, "
- <h2 id='provided-methods'>Provided Methods</h2>
- <div class='methods'>
- ");
- for m in provided.iter() {
- meth(w, *m);
- }
- write!(w, "</div>");
- }
-
- do local_data::get(cache_key) |cache| {
- do cache.unwrap().read |cache| {
- match cache.implementors.find(&it.id) {
- Some(implementors) => {
- write!(w, "
- <h2 id='implementors'>Implementors</h2>
- <ul class='item-list'>
- ");
- for i in implementors.iter() {
- match *i {
- PathType(ref ty) => {
- write!(w, "<li><code>{}</code></li>", *ty);
- }
- OtherType(ref generics, ref trait_, ref for_) => {
- write!(w, "<li><code>impl{} {} for {}</code></li>",
- *generics, *trait_, *for_);
- }
- }
- }
- write!(w, "</ul>");
- }
- None => {}
- }
- }
- }
-}
-
-fn render_method(w: &mut io::Writer, meth: &clean::Item, withlink: bool) {
- fn fun(w: &mut io::Writer, it: &clean::Item, purity: ast::purity,
- g: &clean::Generics, selfty: &clean::SelfTy, d: &clean::FnDecl,
- withlink: bool) {
- write!(w, "{}fn {withlink, select,
- true{<a href='\\#fn.{name}'>{name}</a>}
- other{{name}}
- }{generics}{decl}",
- match purity {
- ast::unsafe_fn => "unsafe ",
- _ => "",
- },
- name = it.name.get_ref().as_slice(),
- generics = *g,
- decl = Method(selfty, d),
- withlink = if withlink {"true"} else {"false"});
- }
- match meth.inner {
- clean::TyMethodItem(ref m) => {
- fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink);
- }
- clean::MethodItem(ref m) => {
- fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink);
- }
- _ => unreachable!()
- }
-}
-
-fn item_struct(w: &mut io::Writer, it: &clean::Item, s: &clean::Struct) {
- write!(w, "<pre class='struct'>");
- render_struct(w, it, Some(&s.generics), s.struct_type, s.fields, "");
- write!(w, "</pre>");
-
- document(w, it);
- render_methods(w, it);
-}
-
-fn item_enum(w: &mut io::Writer, it: &clean::Item, e: &clean::Enum) {
- write!(w, "<pre class='enum'>{}enum {}{}",
- VisSpace(it.visibility),
- it.name.get_ref().as_slice(),
- e.generics);
- if e.variants.len() == 0 {
- write!(w, " \\{\\}");
- } else {
- write!(w, " \\{\n");
- for v in e.variants.iter() {
- let name = v.name.get_ref().as_slice();
- match v.inner {
- clean::VariantItem(ref var) => {
- match var.kind {
- clean::CLikeVariant => write!(w, " {},\n", name),
- clean::TupleVariant(ref tys) => {
- write!(w, " {}(", name);
- for (i, ty) in tys.iter().enumerate() {
- if i > 0 { write!(w, ", ") }
- write!(w, "{}", *ty);
- }
- write!(w, "),\n");
- }
- clean::StructVariant(ref s) => {
- render_struct(w, v, None, s.struct_type, s.fields,
- " ");
- }
- }
- }
- _ => unreachable!()
- }
- }
- write!(w, "\\}");
- }
- write!(w, "</pre>");
-
- document(w, it);
- render_methods(w, it);
-}
-
-fn render_struct(w: &mut io::Writer, it: &clean::Item,
- g: Option<&clean::Generics>,
- ty: doctree::StructType,
- fields: &[clean::Item],
- tab: &str) {
- write!(w, "{}struct {}",
- VisSpace(it.visibility),
- it.name.get_ref().as_slice());
- match g {
- Some(g) => write!(w, "{}", *g),
- None => {}
- }
- match ty {
- doctree::Plain => {
- write!(w, " \\{\n");
- for field in fields.iter() {
- match field.inner {
- clean::StructFieldItem(ref ty) => {
- write!(w, " {}{}: {},\n{}",
- VisSpace(field.visibility),
- field.name.get_ref().as_slice(),
- ty.type_,
- tab);
- }
- _ => unreachable!()
- }
- }
- write!(w, "\\}");
- }
- doctree::Tuple | doctree::Newtype => {
- write!(w, "(");
- for (i, field) in fields.iter().enumerate() {
- if i > 0 { write!(w, ", ") }
- match field.inner {
- clean::StructFieldItem(ref field) => {
- write!(w, "{}", field.type_);
- }
- _ => unreachable!()
- }
- }
- write!(w, ");");
- }
- doctree::Unit => { write!(w, ";"); }
- }
-}
-
-fn render_methods(w: &mut io::Writer, it: &clean::Item) {
- do local_data::get(cache_key) |cache| {
- let cache = cache.unwrap();
- do cache.read |c| {
- match c.impls.find(&it.id) {
- Some(v) => {
- let mut non_trait = v.iter().filter(|i| i.trait_.is_none());
- let non_trait = non_trait.to_owned_vec();
- let mut traits = v.iter().filter(|i| i.trait_.is_some());
- let traits = traits.to_owned_vec();
-
- if non_trait.len() > 0 {
- write!(w, "<h2 id='methods'>Methods</h2>");
- for &i in non_trait.iter() {
- render_impl(w, i);
- }
- }
- if traits.len() > 0 {
- write!(w, "<h2 id='implementations'>Trait \
- Implementations</h2>");
- for &i in traits.iter() {
- render_impl(w, i);
- }
- }
- }
- None => {}
- }
- }
- }
-}
-
-fn render_impl(w: &mut io::Writer, i: &clean::Impl) {
- write!(w, "<h3 class='impl'><code>impl{} ", i.generics);
- let trait_id = match i.trait_ {
- Some(ref ty) => {
- write!(w, "{} for ", *ty);
- match *ty {
- clean::ResolvedPath { id, _ } => Some(id),
- _ => None,
- }
- }
- None => None
- };
- write!(w, "{}</code></h3>", i.for_);
- write!(w, "<div class='methods'>");
- for meth in i.methods.iter() {
- write!(w, "<h4 id='fn.{}' class='method'><code>",
- *meth.name.get_ref());
- render_method(w, meth, false);
- write!(w, "</code></h4>\n");
- match meth.doc_value() {
- Some(s) => {
- write!(w, "<div class='docblock'>{}</div>", Markdown(s));
- loop
- }
- None => {}
- }
-
- // No documentation? Attempt to slurp in the trait's documentation
- let trait_id = match trait_id { Some(id) => id, None => loop };
- do local_data::get(cache_key) |cache| {
- do cache.unwrap().read |cache| {
- let name = meth.name.get_ref().as_slice();
- match cache.traits.find(&trait_id) {
- Some(m) => {
- match m.find_equiv(&name) {
- Some(s) => {
- write!(w, "<div class='docblock'>{}</div>",
- Markdown(s.as_slice()));
- }
- None => {}
- }
- }
- None => {}
- }
- }
- }
- }
- write!(w, "</div>");
-}
-
-fn item_typedef(w: &mut io::Writer, it: &clean::Item, t: &clean::Typedef) {
- write!(w, "<pre class='typedef'>type {}{} = {};</pre>",
- it.name.get_ref().as_slice(),
- t.generics,
- t.type_);
-
- document(w, it);
-}
-
-impl<'self> fmt::Default for Sidebar<'self> {
- fn fmt(s: &Sidebar<'self>, fmt: &mut fmt::Formatter) {
- let cx = s.cx;
- let it = s.item;
- write!(fmt.buf, "<p class='location'>");
- let len = cx.current.len() - if it.is_mod() {1} else {0};
- for (i, name) in cx.current.iter().take(len).enumerate() {
- if i > 0 { write!(fmt.buf, "&\\#8203;::") }
- write!(fmt.buf, "<a href='{}index.html'>{}</a>",
- cx.root_path.slice_to((cx.current.len() - i - 1) * 3), *name);
- }
- write!(fmt.buf, "</p>");
-
- fn block(w: &mut io::Writer, short: &str, longty: &str,
- cur: &clean::Item, cx: &Context) {
- let items = match cx.sidebar.find_equiv(&short) {
- Some(items) => items.as_slice(),
- None => return
- };
- write!(w, "<div class='block {}'><h2>{}</h2>", short, longty);
- for item in items.iter() {
- let class = if cur.name.get_ref() == item &&
- short == shortty(cur) { "current" } else { "" };
- write!(w, "<a class='{ty} {class}' href='{curty, select,
- mod{../}
- other{}
- }{ty, select,
- mod{{name}/index.html}
- other{#.{name}.html}
- }'>{name}</a><br/>",
- ty = short,
- class = class,
- curty = shortty(cur),
- name = item.as_slice());
- }
- write!(w, "</div>");
- }
-
- block(fmt.buf, "mod", "Modules", it, cx);
- block(fmt.buf, "struct", "Structs", it, cx);
- block(fmt.buf, "enum", "Enums", it, cx);
- block(fmt.buf, "trait", "Traits", it, cx);
- block(fmt.buf, "fn", "Functions", it, cx);
- }
-}
-
-fn build_sidebar(m: &clean::Module) -> HashMap<~str, ~[~str]> {
- let mut map = HashMap::new();
- for item in m.items.iter() {
- let short = shortty(item);
- let myname = match item.name {
- None => loop,
- Some(ref s) => s.to_owned(),
- };
- let v = map.find_or_insert_with(short.to_owned(), |_| ~[]);
- v.push(myname);
- }
-
- for (_, items) in map.mut_iter() {
- sort::quick_sort(*items, |i1, i2| i1 < i2);
- }
- return map;
-}
+++ /dev/null
-/*! jQuery v2.0.3 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
-//@ sourceMappingURL=jquery-2.0.3.min.map
-*/
-(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],p="2.0.3",f=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:p,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return f.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,p,f,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=st(),k=st(),N=st(),E=!1,S=function(e,t){return e===t?(E=!0,0):0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],q=L.pop,H=L.push,O=L.push,F=L.slice,P=L.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",W="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",$=W.replace("w","w#"),B="\\["+M+"*("+W+")"+M+"*(?:([*^$|!~]?=)"+M+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+$+")|)|)"+M+"*\\]",I=":("+W+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+B.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=RegExp("^"+M+"*,"+M+"*"),X=RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=RegExp(M+"*[+~]"),Y=RegExp("="+M+"*([^\\]'\"]*)"+M+"*\\]","g"),V=RegExp(I),G=RegExp("^"+$+"$"),J={ID:RegExp("^#("+W+")"),CLASS:RegExp("^\\.("+W+")"),TAG:RegExp("^("+W.replace("w","w*")+")"),ATTR:RegExp("^"+B),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:RegExp("^(?:"+R+")$","i"),needsContext:RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Q=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Z=/^(?:input|select|textarea|button)$/i,et=/^h\d$/i,tt=/'|\\/g,nt=RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),rt=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{O.apply(L=F.call(b.childNodes),b.childNodes),L[b.childNodes.length].nodeType}catch(it){O={apply:L.length?function(e,t){H.apply(e,F.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function ot(e,t,r,i){var o,s,a,u,l,f,g,m,x,w;if((t?t.ownerDocument||t:b)!==p&&c(t),t=t||p,r=r||[],!e||"string"!=typeof e)return r;if(1!==(u=t.nodeType)&&9!==u)return[];if(h&&!i){if(o=K.exec(e))if(a=o[1]){if(9===u){if(s=t.getElementById(a),!s||!s.parentNode)return r;if(s.id===a)return r.push(s),r}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(a))&&y(t,s)&&s.id===a)return r.push(s),r}else{if(o[2])return O.apply(r,t.getElementsByTagName(e)),r;if((a=o[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(a)),r}if(n.qsa&&(!d||!d.test(e))){if(m=g=v,x=t,w=9===u&&e,1===u&&"object"!==t.nodeName.toLowerCase()){f=gt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=f.length;while(l--)f[l]=m+mt(f[l]);x=U.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,r,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function at(e){return e[v]=!0,e}function ut(e){var t=p.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function lt(e,t){var n=e.split("|"),r=e.length;while(r--)i.attrHandle[n[r]]=t}function ct(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return at(function(t){return t=+t,at(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}s=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},n=ot.support={},c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:b,r=t.defaultView;return t!==p&&9===t.nodeType&&t.documentElement?(p=t,f=t.documentElement,h=!s(t),r&&r.attachEvent&&r!==r.top&&r.attachEvent("onbeforeunload",function(){c()}),n.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ut(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),n.getById=ut(function(e){return f.appendChild(e).id=v,!t.getElementsByName||!t.getElementsByName(v).length}),n.getById?(i.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){return e.getAttribute("id")===t}}):(delete i.find.ID,i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=n.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.CLASS=n.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&h?t.getElementsByClassName(e):undefined},g=[],d=[],(n.qsa=Q.test(t.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||d.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll(":checked").length||d.push(":checked")}),ut(function(e){var n=t.createElement("input");n.setAttribute("type","hidden"),e.appendChild(n).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&d.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||d.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),d.push(",.*:")})),(n.matchesSelector=Q.test(m=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&ut(function(e){n.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",I)}),d=d.length&&RegExp(d.join("|")),g=g.length&&RegExp(g.join("|")),y=Q.test(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},S=f.compareDocumentPosition?function(e,r){if(e===r)return E=!0,0;var i=r.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(r);return i?1&i||!n.sortDetached&&r.compareDocumentPosition(e)===i?e===t||y(b,e)?-1:r===t||y(b,r)?1:l?P.call(l,e)-P.call(l,r):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],u=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:l?P.call(l,e)-P.call(l,n):0;if(o===s)return ct(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)u.unshift(r);while(a[i]===u[i])i++;return i?ct(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):p},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Y,"='$1']"),!(!n.matchesSelector||!h||g&&g.test(t)||d&&d.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return ot(t,p,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==p&&c(e);var r=i.attrHandle[t.toLowerCase()],o=r&&A.call(i.attrHandle,t.toLowerCase())?r(e,t,!h):undefined;return o===undefined?n.attributes||!h?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null:o},ot.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ot.uniqueSort=function(e){var t,r=[],i=0,o=0;if(E=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(S),E){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return e},o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=ot.selectors={cacheLength:50,createPseudo:at,match:J,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(nt,rt),e[3]=(e[4]||e[5]||"").replace(nt,rt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ot.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ot.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return J.CHILD.test(e[0])?null:(e[3]&&e[4]!==undefined?e[2]=e[4]:n&&V.test(n)&&(t=gt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(nt,rt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){p=t;while(p=p[g])if(a?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[v]||(m[v]={}),l=c[e]||[],h=l[0]===w&&l[1],f=l[0]===w&&l[2],p=h&&m.childNodes[h];while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[w,h,f];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)f=l[1];else while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if((a?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(x&&((p[v]||(p[v]={}))[e]=[w,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);return r[v]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?at(function(e,n){var i,o=r(e,t),s=o.length;while(s--)i=P.call(e,o[s]),e[i]=!(n[i]=o[s])}):function(e){return r(e,0,n)}):r}},pseudos:{not:at(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?at(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:at(function(e){return function(t){return ot(e,t).length>0}}),contains:at(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:at(function(e){return G.test(e||"")||ot.error("unsupported lang: "+e),e=e.replace(nt,rt).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return et.test(e.nodeName)},input:function(e){return Z.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},i.pseudos.nth=i.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=pt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=ft(t);function dt(){}dt.prototype=i.filters=i.pseudos,i.setFilters=new dt;function gt(e,t){var n,r,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=i.preFilter;while(a){(!n||(r=_.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),u.push(o=[])),n=!1,(r=X.exec(a))&&(n=r.shift(),o.push({value:n,type:r[0].replace(z," ")}),a=a.slice(n.length));for(s in i.filter)!(r=J[s].exec(a))||l[s]&&!(r=l[s](r))||(n=r.shift(),o.push({value:n,type:s,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ot.error(e):k(e,u).slice(0)}function mt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function yt(e,t,n){var i=t.dir,o=n&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,a){var u,l,c,p=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[v]||(t[v]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function vt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function bt(e,t,n,r,i,o){return r&&!r[v]&&(r=bt(r)),i&&!i[v]&&(i=bt(i,o)),at(function(o,s,a,u){var l,c,p,f=[],h=[],d=s.length,g=o||Ct(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:xt(g,f,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=xt(y,h),r(l,[],a,u),c=l.length;while(c--)(p=l[c])&&(y[h[c]]=!(m[h[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?P.call(o,p):f[c])>-1&&(o[l]=!(s[l]=p))}}else y=xt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function wt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=yt(function(e){return e===t},a,!0),p=yt(function(e){return P.call(t,e)>-1},a,!0),f=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])f=[yt(vt(f),n)];else{if(n=i.filter[e[l].type].apply(null,e[l].matches),n[v]){for(r=++l;o>r;r++)if(i.relative[e[r].type])break;return bt(l>1&&vt(f),l>1&&mt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&wt(e.slice(l,r)),o>r&&wt(e=e.slice(r)),o>r&&mt(e))}f.push(n)}return vt(f)}function Tt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,f,h){var d,g,m,y=[],v=0,x="0",b=a&&[],T=null!=h,C=u,k=a||s&&i.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(u=l!==p&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){f.push(d);break}T&&(w=N,r=++n)}o&&((d=!m&&d)&&v--,a&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,c);if(a){if(v>0)while(x--)b[x]||y[x]||(y[x]=q.call(f));y=xt(y)}O.apply(f,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(f)}return T&&(w=N,u=C),b};return o?at(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=gt(e)),n=t.length;while(n--)o=wt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Tt(i,r))}return o};function Ct(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function kt(e,t,r,o){var s,u,l,c,p,f=gt(e);if(!o&&1===f.length){if(u=f[0]=f[0].slice(0),u.length>2&&"ID"===(l=u[0]).type&&n.getById&&9===t.nodeType&&h&&i.relative[u[1].type]){if(t=(i.find.ID(l.matches[0].replace(nt,rt),t)||[])[0],!t)return r;e=e.slice(u.shift().value.length)}s=J.needsContext.test(e)?0:u.length;while(s--){if(l=u[s],i.relative[c=l.type])break;if((p=i.find[c])&&(o=p(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&mt(u),!e)return O.apply(r,o),r;break}}}return a(e,f)(o,t,!h,r,U.test(e)),r}n.sortStable=v.split("").sort(S).join("")===v,n.detectDuplicates=E,c(),n.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(p.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||lt("type|href|height|width",function(e,t,n){return n?undefined:e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||lt("value",function(e,t,n){return n||"input"!==e.nodeName.toLowerCase()?undefined:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||lt(R,function(e,t,n){var r;return n?undefined:(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===!0?t.toLowerCase():null}),x.find=ot,x.expr=ot.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ot.uniqueSort,x.text=ot.getText,x.isXMLDoc=ot.isXML,x.contains=ot.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(p){for(t=e.memory&&p,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(p[0],p[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!a||n&&!u||(t=t||[],t=[e,t.slice?t.slice():t],r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,q,H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))x.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){var r;return t===undefined||t&&"string"==typeof t&&n===undefined?(r=this.get(e,t),r!==undefined?r:this.get(e,x.camelCase(t))):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(t===undefined)this.cache[o]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):(i=x.camelCase(t),t in s?r=[t,i]:(r=i,r=r in s?[r]:r.match(w)||[])),n=r.length;while(n--)delete s[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}},L=new F,q=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||q.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return q.access(e,t,n)},_removeData:function(e,t){q.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!q.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.slice(5)),P(i,r,s[r]));q.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:H.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=q.get(e,t),n&&(!r||x.isArray(n)?r=q.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t)
-};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=q.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,i=0,o=x(this),s=e.match(w)||[];while(t=s[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,p,f,h,d,g,m,y=q.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(f=x.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=x.event.special[d]||{},p=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,f.setup&&f.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),f.add&&(f.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,p):h.push(p),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,p,f,h,d,g,m=q.hasData(e)&&q.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){p=x.event.special[h]||{},h=(r?p.delegateType:p.bindType)||h,f=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=f.length;while(o--)c=f[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(f.splice(o,1),c.selector&&f.delegateCount--,p.remove&&p.remove.call(e,c));s&&!f.length&&(p.teardown&&p.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,q.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,p,f,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),f=x.event.special[d]||{},i||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!i&&!f.noBubble&&!x.isWindow(r)){for(l=f.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:f.bindType||d,p=(q.get(a,"events")||{})[t.type]&&q.get(a,"handle"),p&&p.apply(a,n),p=c&&a[c],p&&x.acceptData(a)&&p.apply&&p.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||f._default&&f._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(q.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,s=e,a=this.fixHooks[i];a||(this.fixHooks[i]=a=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new x.Event(s),t=r.length;while(t--)n=r[t],e[n]=s[n];return e.target||(e.target=o),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,s):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=/^(?:parents|prev(?:Until|All))/,Q=x.expr.match.needsContext,K={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(et(this,e||[],!0))},filter:function(e){return this.pushStack(et(this,e||[],!1))},is:function(e){return!!et(this,"string"==typeof e&&Q.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],s=Q.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function Z(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return Z(e,"nextSibling")},prev:function(e){return Z(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return e.contentDocument||x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(K[e]||x.unique(i),J.test(e)&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function et(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,nt=/<([\w:]+)/,rt=/<|&#?\w+;/,it=/<(?:script|style|link)/i,ot=/^(?:checkbox|radio)$/i,st=/checked\s*(?:[^=]|=\s*.checked.)/i,at=/^$|\/(?:java|ecma)script/i,ut=/^true\/(.*)/,lt=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ct={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ct.optgroup=ct.option,ct.tbody=ct.tfoot=ct.colgroup=ct.caption=ct.thead,ct.th=ct.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(mt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&dt(mt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(mt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!ct[(nt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(tt,"<$1></$2>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(mt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=f.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,p=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&st.test(d))return this.each(function(r){var i=p.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(mt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,mt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,ht),l=0;s>l;l++)a=o[l],at.test(a.type||"")&&!q.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(lt,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=mt(a),o=mt(e),r=0,i=o.length;i>r;r++)yt(o[r],s[r]);if(t)if(n)for(o=o||mt(e),s=s||mt(a),r=0,i=o.length;i>r;r++)gt(o[r],s[r]);else gt(e,a);return s=mt(a,"script"),s.length>0&&dt(s,!u&&mt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,p=e.length,f=t.createDocumentFragment(),h=[];for(;p>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(rt.test(i)){o=o||f.appendChild(t.createElement("div")),s=(nt.exec(i)||["",""])[1].toLowerCase(),a=ct[s]||ct._default,o.innerHTML=a[1]+i.replace(tt,"<$1></$2>")+a[2],l=a[0];while(l--)o=o.lastChild;x.merge(h,o.childNodes),o=f.firstChild,o.textContent=""}else h.push(t.createTextNode(i));f.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(f.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return f},cleanData:function(e){var t,n,r,i,o,s,a=x.event.special,u=0;for(;(n=e[u])!==undefined;u++){if(F.accepts(n)&&(o=n[q.expando],o&&(t=q.cache[o]))){if(r=Object.keys(t.events||{}),r.length)for(s=0;(i=r[s])!==undefined;s++)a[i]?x.event.remove(n,i):x.removeEvent(n,i,t.handle);q.cache[o]&&delete q.cache[o]}delete L.cache[n[L.expando]]}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}});function pt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ht(e){var t=ut.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function dt(e,t){var n=e.length,r=0;for(;n>r;r++)q.set(e[r],"globalEval",!t||q.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(q.hasData(e)&&(o=q.access(e),s=q.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function mt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function yt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ot.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var vt,xt,bt=/^(none|table(?!-c[ea]).+)/,wt=/^margin/,Tt=RegExp("^("+b+")(.*)$","i"),Ct=RegExp("^("+b+")(?!px)[a-z%]+$","i"),kt=RegExp("^([+-])=("+b+")","i"),Nt={BODY:"block"},Et={position:"absolute",visibility:"hidden",display:"block"},St={letterSpacing:0,fontWeight:400},jt=["Top","Right","Bottom","Left"],Dt=["Webkit","O","Moz","ms"];function At(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Dt.length;while(i--)if(t=Dt[i]+n,t in e)return t;return r}function Lt(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function qt(t){return e.getComputedStyle(t,null)}function Ht(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=q.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=q.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&q.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=qt(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return Ht(this,!0)},hide:function(){return Ht(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Lt(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=vt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=At(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=kt.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=At(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=vt(e,t,r)),"normal"===i&&t in St&&(i=St[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),vt=function(e,t,n){var r,i,o,s=n||qt(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Ct.test(a)&&wt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ot(e,t,n){var r=Tt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ft(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+jt[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+jt[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+jt[o]+"Width",!0,i))):(s+=x.css(e,"padding"+jt[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+jt[o]+"Width",!0,i)));return s}function Pt(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=qt(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=vt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Ct.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ft(e,t,n||(s?"border":"content"),r,o)+"px"}function Rt(e){var t=o,n=Nt[e];return n||(n=Mt(e,t),"none"!==n&&n||(xt=(xt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(xt[0].contentWindow||xt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=Mt(e,t),xt.detach()),Nt[e]=n),n}function Mt(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,t){x.cssHooks[t]={get:function(e,n,r){return n?0===e.offsetWidth&&bt.test(x.css(e,"display"))?x.swap(e,Et,function(){return Pt(e,t,r)}):Pt(e,t,r):undefined},set:function(e,n,r){var i=r&&qt(e);return Ot(e,n,r?Ft(e,t,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,t){return t?x.swap(e,{display:"inline-block"},vt,[e,"marginRight"]):undefined}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,t){x.cssHooks[t]={get:function(e,n){return n?(n=vt(e,t),Ct.test(n)?x(e).position()[t]+"px":n):undefined}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+jt[r]+t]=o[r]||o[r-2]||o[0];return i}},wt.test(e)||(x.cssHooks[e+t].set=Ot)});var Wt=/%20/g,$t=/\[\]$/,Bt=/\r?\n/g,It=/^(?:submit|button|image|reset|file)$/i,zt=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&zt.test(this.nodeName)&&!It.test(e)&&(this.checked||!ot.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(Bt,"\r\n")}}):{name:t.name,value:n.replace(Bt,"\r\n")}}).get()}}),x.param=function(e,t){var n,r=[],i=function(e,t){t=x.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(t===undefined&&(t=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){i(this.name,this.value)});else for(n in e)_t(n,e[n],t,i);return r.join("&").replace(Wt,"+")};function _t(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||$t.test(e)?r(e,i):_t(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)_t(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)
-},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var Xt,Ut,Yt=x.now(),Vt=/\?/,Gt=/#.*$/,Jt=/([?&])_=[^&]*/,Qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Kt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Zt=/^(?:GET|HEAD)$/,en=/^\/\//,tn=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,nn=x.fn.load,rn={},on={},sn="*/".concat("*");try{Ut=i.href}catch(an){Ut=o.createElement("a"),Ut.href="",Ut=Ut.href}Xt=tn.exec(Ut.toLowerCase())||[];function un(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function ln(e,t,n,r){var i={},o=e===on;function s(a){var u;return i[a]=!0,x.each(e[a]||[],function(e,a){var l=a(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):undefined:(t.dataTypes.unshift(l),s(l),!1)}),u}return s(t.dataTypes[0])||!i["*"]&&s("*")}function cn(e,t){var n,r,i=x.ajaxSettings.flatOptions||{};for(n in t)t[n]!==undefined&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,t,n){if("string"!=typeof e&&nn)return nn.apply(this,arguments);var r,i,o,s=this,a=e.indexOf(" ");return a>=0&&(r=e.slice(a),e=e.slice(0,a)),x.isFunction(t)?(n=t,t=undefined):t&&"object"==typeof t&&(i="POST"),s.length>0&&x.ajax({url:e,type:i,dataType:"html",data:t}).done(function(e){o=arguments,s.html(r?x("<div>").append(x.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ut,type:"GET",isLocal:Kt.test(Xt[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":sn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?cn(cn(e,x.ajaxSettings),t):cn(x.ajaxSettings,e)},ajaxPrefilter:un(rn),ajaxTransport:un(on),ajax:function(e,t){"object"==typeof e&&(t=e,e=undefined),t=t||{};var n,r,i,o,s,a,u,l,c=x.ajaxSetup({},t),p=c.context||c,f=c.context&&(p.nodeType||p.jquery)?x(p):x.event,h=x.Deferred(),d=x.Callbacks("once memory"),g=c.statusCode||{},m={},y={},v=0,b="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===v){if(!o){o={};while(t=Qt.exec(i))o[t[1].toLowerCase()]=t[2]}t=o[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===v?i:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return v||(e=y[n]=y[n]||e,m[e]=t),this},overrideMimeType:function(e){return v||(c.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>v)for(t in e)g[t]=[g[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||b;return n&&n.abort(t),k(0,t),this}};if(h.promise(T).complete=d.add,T.success=T.done,T.error=T.fail,c.url=((e||c.url||Ut)+"").replace(Gt,"").replace(en,Xt[1]+"//"),c.type=t.method||t.type||c.method||c.type,c.dataTypes=x.trim(c.dataType||"*").toLowerCase().match(w)||[""],null==c.crossDomain&&(a=tn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===Xt[1]&&a[2]===Xt[2]&&(a[3]||("http:"===a[1]?"80":"443"))===(Xt[3]||("http:"===Xt[1]?"80":"443")))),c.data&&c.processData&&"string"!=typeof c.data&&(c.data=x.param(c.data,c.traditional)),ln(rn,c,t,T),2===v)return T;u=c.global,u&&0===x.active++&&x.event.trigger("ajaxStart"),c.type=c.type.toUpperCase(),c.hasContent=!Zt.test(c.type),r=c.url,c.hasContent||(c.data&&(r=c.url+=(Vt.test(r)?"&":"?")+c.data,delete c.data),c.cache===!1&&(c.url=Jt.test(r)?r.replace(Jt,"$1_="+Yt++):r+(Vt.test(r)?"&":"?")+"_="+Yt++)),c.ifModified&&(x.lastModified[r]&&T.setRequestHeader("If-Modified-Since",x.lastModified[r]),x.etag[r]&&T.setRequestHeader("If-None-Match",x.etag[r])),(c.data&&c.hasContent&&c.contentType!==!1||t.contentType)&&T.setRequestHeader("Content-Type",c.contentType),T.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+("*"!==c.dataTypes[0]?", "+sn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)T.setRequestHeader(l,c.headers[l]);if(c.beforeSend&&(c.beforeSend.call(p,T,c)===!1||2===v))return T.abort();b="abort";for(l in{success:1,error:1,complete:1})T[l](c[l]);if(n=ln(on,c,t,T)){T.readyState=1,u&&f.trigger("ajaxSend",[T,c]),c.async&&c.timeout>0&&(s=setTimeout(function(){T.abort("timeout")},c.timeout));try{v=1,n.send(m,k)}catch(C){if(!(2>v))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,t,o,a){var l,m,y,b,w,C=t;2!==v&&(v=2,s&&clearTimeout(s),n=undefined,i=a||"",T.readyState=e>0?4:0,l=e>=200&&300>e||304===e,o&&(b=pn(c,T,o)),b=fn(c,b,T,l),l?(c.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(x.lastModified[r]=w),w=T.getResponseHeader("etag"),w&&(x.etag[r]=w)),204===e||"HEAD"===c.type?C="nocontent":304===e?C="notmodified":(C=b.state,m=b.data,y=b.error,l=!y)):(y=C,(e||!C)&&(C="error",0>e&&(e=0))),T.status=e,T.statusText=(t||C)+"",l?h.resolveWith(p,[m,C,T]):h.rejectWith(p,[T,C,y]),T.statusCode(g),g=undefined,u&&f.trigger(l?"ajaxSuccess":"ajaxError",[T,c,l?m:y]),d.fireWith(p,[T,C]),u&&(f.trigger("ajaxComplete",[T,c]),--x.active||x.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,t){return x.get(e,undefined,t,"script")}}),x.each(["get","post"],function(e,t){x[t]=function(e,n,r,i){return x.isFunction(n)&&(i=i||r,r=n,n=undefined),x.ajax({url:e,type:t,dataType:i,data:n,success:r})}});function pn(e,t,n){var r,i,o,s,a=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),r===undefined&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in a)if(a[i]&&a[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}s||(s=i)}o=o||s}return o?(o!==u[0]&&u.unshift(o),n[o]):undefined}function fn(e,t,n,r){var i,o,s,a,u,l={},c=e.dataTypes.slice();if(c[1])for(s in e.converters)l[s.toLowerCase()]=e.converters[s];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(s=l[u+" "+o]||l["* "+o],!s)for(i in l)if(a=i.split(" "),a[1]===o&&(s=l[u+" "+a[0]]||l["* "+a[0]])){s===!0?s=l[i]:l[i]!==!0&&(o=a[0],c.unshift(a[1]));break}if(s!==!0)if(s&&e["throws"])t=s(t);else try{t=s(t)}catch(p){return{state:"parsererror",error:s?p:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===undefined&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),x.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(r,i){t=x("<script>").prop({async:!0,charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&i("error"===e.type?404:200,e.type)}),o.head.appendChild(t[0])},abort:function(){n&&n()}}}});var hn=[],dn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=hn.pop()||x.expando+"_"+Yt++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,s,a=t.jsonp!==!1&&(dn.test(t.url)?"url":"string"==typeof t.data&&!(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&dn.test(t.data)&&"data");return a||"jsonp"===t.dataTypes[0]?(i=t.jsonpCallback=x.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,a?t[a]=t[a].replace(dn,"$1"+i):t.jsonp!==!1&&(t.url+=(Vt.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return s||x.error(i+" was not called"),s[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){s=arguments},r.always(function(){e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,hn.push(i)),s&&x.isFunction(o)&&o(s[0]),s=o=undefined}),"script"):undefined}),x.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(e){}};var gn=x.ajaxSettings.xhr(),mn={0:200,1223:204},yn=0,vn={};e.ActiveXObject&&x(e).on("unload",function(){for(var e in vn)vn[e]();vn=undefined}),x.support.cors=!!gn&&"withCredentials"in gn,x.support.ajax=gn=!!gn,x.ajaxTransport(function(e){var t;return x.support.cors||gn&&!e.crossDomain?{send:function(n,r){var i,o,s=e.xhr();if(s.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(i in e.xhrFields)s[i]=e.xhrFields[i];e.mimeType&&s.overrideMimeType&&s.overrideMimeType(e.mimeType),e.crossDomain||n["X-Requested-With"]||(n["X-Requested-With"]="XMLHttpRequest");for(i in n)s.setRequestHeader(i,n[i]);t=function(e){return function(){t&&(delete vn[o],t=s.onload=s.onerror=null,"abort"===e?s.abort():"error"===e?r(s.status||404,s.statusText):r(mn[s.status]||s.status,s.statusText,"string"==typeof s.responseText?{text:s.responseText}:undefined,s.getAllResponseHeaders()))}},s.onload=t(),s.onerror=t("error"),t=vn[o=yn++]=t("abort"),s.send(e.hasContent&&e.data||null)},abort:function(){t&&t()}}:undefined});var xn,bn,wn=/^(?:toggle|show|hide)$/,Tn=RegExp("^(?:([+-])=|)("+b+")([a-z%]*)$","i"),Cn=/queueHooks$/,kn=[An],Nn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Tn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),s=(x.cssNumber[e]||"px"!==o&&+r)&&Tn.exec(x.css(n.elem,e)),a=1,u=20;if(s&&s[3]!==o){o=o||s[3],i=i||[],s=+r||1;do a=a||".5",s/=a,x.style(n.elem,e,s+o);while(a!==(a=n.cur()/r)&&1!==a&&--u)}return i&&(s=n.start=+s||+r||0,n.unit=o,n.end=i[1]?s+(i[1]+1)*i[2]:+i[2]),n}]};function En(){return setTimeout(function(){xn=undefined}),xn=x.now()}function Sn(e,t,n){var r,i=(Nn[t]||[]).concat(Nn["*"]),o=0,s=i.length;for(;s>o;o++)if(r=i[o].call(n,t,e))return r}function jn(e,t,n){var r,i,o=0,s=kn.length,a=x.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=xn||En(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,s=0,u=l.tweens.length;for(;u>s;s++)l.tweens[s].run(o);return a.notifyWith(e,[l,o,n]),1>o&&u?n:(a.resolveWith(e,[l]),!1)},l=a.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:xn||En(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?a.resolveWith(e,[l,t]):a.rejectWith(e,[l,t]),this}}),c=l.props;for(Dn(c,l.opts.specialEasing);s>o;o++)if(r=kn[o].call(l,e,c,l.opts))return r;return x.map(c,Sn,l),x.isFunction(l.opts.start)&&l.opts.start.call(e,l),x.fx.timer(x.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function Dn(e,t){var n,r,i,o,s;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),s=x.cssHooks[r],s&&"expand"in s){o=s.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(jn,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Nn[n]=Nn[n]||[],Nn[n].unshift(t)},prefilter:function(e,t){t?kn.unshift(e):kn.push(e)}});function An(e,t,n){var r,i,o,s,a,u,l=this,c={},p=e.style,f=e.nodeType&&Lt(e),h=q.get(e,"fxshow");n.queue||(a=x._queueHooks(e,"fx"),null==a.unqueued&&(a.unqueued=0,u=a.empty.fire,a.empty.fire=function(){a.unqueued||u()}),a.unqueued++,l.always(function(){l.always(function(){a.unqueued--,x.queue(e,"fx").length||a.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(p.display="inline-block")),n.overflow&&(p.overflow="hidden",l.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],wn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show")){if("show"!==i||!h||h[r]===undefined)continue;f=!0}c[r]=h&&h[r]||x.style(e,r)}if(!x.isEmptyObject(c)){h?"hidden"in h&&(f=h.hidden):h=q.access(e,"fxshow",{}),o&&(h.hidden=!f),f?x(e).show():l.done(function(){x(e).hide()}),l.done(function(){var t;q.remove(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)s=Sn(f?h[r]:0,r,l),r in h||(h[r]=s.start,f&&(s.end=s.start,s.start="width"===r||"height"===r?1:0))}}function Ln(e,t,n,r,i){return new Ln.prototype.init(e,t,n,r,i)}x.Tween=Ln,Ln.prototype={constructor:Ln,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=Ln.propHooks[this.prop];return e&&e.get?e.get(this):Ln.propHooks._default.get(this)},run:function(e){var t,n=Ln.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ln.propHooks._default.set(this),this}},Ln.prototype.init.prototype=Ln.prototype,Ln.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Ln.propHooks.scrollTop=Ln.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(qn(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Lt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),s=function(){var t=jn(this,x.extend({},e),o);(i||q.get(this,"finish"))&&t.stop(!0)};return s.finish=s,i||o.queue===!1?this.each(s):this.queue(o.queue,s)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=undefined),t&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,i=null!=e&&e+"queueHooks",o=x.timers,s=q.get(this);if(i)s[i]&&s[i].stop&&r(s[i]);else for(i in s)s[i]&&s[i].stop&&Cn.test(i)&&r(s[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));(t||!n)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=q.get(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,s=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;s>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function qn(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=jt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:qn("show"),slideUp:qn("hide"),slideToggle:qn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=Ln.prototype.init,x.fx.tick=function(){var e,t=x.timers,n=0;for(xn=x.now();t.length>n;n++)e=t[n],e()||t[n]!==e||t.splice(n--,1);t.length||x.fx.stop(),xn=undefined},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){bn||(bn=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(bn),bn=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===undefined?this:this.each(function(t){x.offset.setOffset(this,e,t)});var t,n,i=this[0],o={top:0,left:0},s=i&&i.ownerDocument;if(s)return t=s.documentElement,x.contains(t,i)?(typeof i.getBoundingClientRect!==r&&(o=i.getBoundingClientRect()),n=Hn(s),{top:o.top+n.pageYOffset-t.clientTop,left:o.left+n.pageXOffset-t.clientLeft}):o},x.offset={setOffset:function(e,t,n){var r,i,o,s,a,u,l,c=x.css(e,"position"),p=x(e),f={};"static"===c&&(e.style.position="relative"),a=p.offset(),o=x.css(e,"top"),u=x.css(e,"left"),l=("absolute"===c||"fixed"===c)&&(o+u).indexOf("auto")>-1,l?(r=p.position(),s=r.top,i=r.left):(s=parseFloat(o)||0,i=parseFloat(u)||0),x.isFunction(t)&&(t=t.call(e,n,a)),null!=t.top&&(f.top=t.top-a.top+s),null!=t.left&&(f.left=t.left-a.left+i),"using"in t?t.using.call(e,f):p.css(f)}},x.fn.extend({position:function(){if(this[0]){var e,t,n=this[0],r={top:0,left:0};return"fixed"===x.css(n,"position")?t=n.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(r=e.offset()),r.top+=x.css(e[0],"borderTopWidth",!0),r.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-r.top-x.css(n,"marginTop",!0),left:t.left-r.left-x.css(n,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,n){var r="pageYOffset"===n;x.fn[t]=function(i){return x.access(this,function(t,i,o){var s=Hn(t);return o===undefined?s?s[n]:t[i]:(s?s.scrollTo(r?e.pageXOffset:o,r?o:e.pageYOffset):t[i]=o,undefined)},t,i,arguments.length,null)}});function Hn(e){return x.isWindow(e)?e:9===e.nodeType&&e.defaultView}x.each({Height:"height",Width:"width"},function(e,t){x.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){x.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),s=n||(r===!0||i===!0?"margin":"border");return x.access(this,function(t,n,r){var i;return x.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):r===undefined?x.css(t,n,s):x.style(t,n,r,s)},t,o?r:undefined,o,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}),"object"==typeof e&&"object"==typeof e.document&&(e.jQuery=e.$=x)})(window);
+++ /dev/null
-/**
- * Copyright 2013 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.
- */
-
-@import "normalize.css";
-
-* {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-/* Fonts */
-
-body {
- font: 13px Arial, sans-serif;
- line-height: 165%;
-}
-
-h1, .sidebar .location {
- font: 700 22px "Oswald", Arial, sans-serif;
-}
-
-h2, h3, h4 {
- font: 700 16px "Oswald", Arial, sans-serif;
- text-transform: uppercase;
-}
-
-h2 code, h3 code, h4 code {
- text-transform: none;
- font-size: 1.2em;
-}
-
-code, pre, h1.fqn {
- font: 15px "Inconsolata", "Consolas", "Courier New", monospace;
-}
-h1.fqn {
- font-size: 26px;
- font-weight: normal;
-}
-
-nav {
- font: 700 26px "Oswald", Arial, sans-serif;
- text-transform: uppercase;
-}
-
-nav.sub {
- padding-top: 20px;
- font: 700 16px "Oswald", Arial, sans-serif;
- text-transform: uppercase;
- text-align: right;
-}
-
-/* General structure */
-
-html, body {
- min-height: 100%;
- height: 100%;
-}
-
-body {
- position: relative;
- height: auto;
- padding-bottom: 20px;
-}
-
-.sidebar {
- width: 200px;
- position: absolute;
- left: 0;
- top: 0;
- min-height: 100%;
-}
-
-.content, nav { max-width: 960px; }
-
-/* Everything else */
-
-.js-only, .hidden { display: none; }
-
-.sidebar {
- background: #e9e9e9;
- padding: 10px;
-}
-
-.sidebar img {
- margin: 20px auto;
- display: block;
-}
-
-.sidebar .location { margin-bottom: 10px; }
-.sidebar .block, pre { background: #fff; }
-.sidebar .block, pre, .content { border-bottom: 2px solid black; }
-.trait { border-color: #fcae2b !important; }
-.mod { border-color: #809fc7 !important; }
-.enum { border-color: #93bc99 !important; }
-.struct { border-color: #e53700 !important; }
-.fn { border-color: #a2777f !important; }
-
-.block {
- padding: 10px;
- margin-bottom: 10px;
-}
-.block h2 { margin-top: 0; }
-
-.content {
- background: #f3f3f3;
- padding: 20px 20px 20px 40px;
-}
-.content h1 { margin-top: 0; }
-.content h1, .content h2 { margin-left: -20px; }
-.content pre { padding: 20px; }
-
-.content .highlighted {
- cursor: pointer;
- color: #000 !important;
- background-color: #ccc;
-}
-.content .highlighted a { color: #000 !important; }
-.content .highlighted.trait { background-color: #fece7e; }
-.content .highlighted.mod { background-color: #afc6e4; }
-.content .highlighted.enum { background-color: #b4d1b9; }
-.content .highlighted.struct { background-color: #e7b1a0; }
-.content .highlighted.fn { background-color: #c6afb3; }
-
-.docblock.short.nowrap {
- display: block;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-.docblock.short p {
- overflow: hidden;
- text-overflow: ellipsis;
- margin: 0;
-}
-
-.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
- margin-left: 0;
-}
-
-.docblock h1 { font-size: 1.1em; }
-.docblock h2 { font-size: 1.05em; }
-.docblock h3, .docblock h4, .docblock h5 { font-size: 1em; }
-
-.content .source { float: right; }
-.content table {
- border-spacing: 0 5px;
- border-collapse: separate;
-}
-.content td { vertical-align: top; }
-.content td:first-child { padding-right: 20px; }
-.content td p:first-child { margin-top: 0; }
-.content td h1, .content td h2 { margin-left: 0; font-size: 1.1em; }
-
-.content .item-list {
- list-style-type: none;
- padding: 0;
-}
-
-.content .item-list li { margin-bottom: 3px; }
-
-.content .multi-column {
- -moz-column-count: 5;
- -moz-column-gap: 2.5em;
- -webkit-column-count: 5;
- -webkit-column-gap: 2.5em;
- column-count: 5;
- column-gap: 2.5em;
-}
-.content .multi-column li { width: 100%; display: inline-block; }
-
-.content .method { font-size: 1em; }
-.content .methods { margin-left: 20px; }
-.content .methods .docblock { margin-left: 20px; }
-
-nav {
- border-bottom: 1px solid #e0e0e0;
- padding-bottom: 10px;
- margin-bottom: 10px;
-}
-nav.main {
- padding: 20px 0;
- text-align: center;
-}
-nav.main .current {
- border-top: 1px solid #000;
- border-bottom: 1px solid #000;
-}
-nav.main .separator {
- border: 1px solid #000;
- display: inline-block;
- height: 23px;
- margin: 0 20px;
-}
-nav.sum { text-align: right; }
-nav.sub form { display: inline; }
-
-nav, .content {
- margin-left: 220px;
- margin-right: 20px;
-}
-
-a {
- text-decoration: none;
- color: #000;
-}
-
-.content a, .block a.current { font-weight: bold; }
-
-.content a.trait, .block a.current.trait { color: #ed9603; }
-.content a.mod, .block a.current.mod { color: #4d76ae; }
-.content a.enum, .block a.current.enum { color: #5e9766; }
-.content a.struct, .block a.current.struct { color: #e53700; }
-.content a.fn, .block a.current.fn { color: #8c6067; }
-
-.search-input {
- border: 2px solid #f2f2f2;
- border-radius: 2px;
- width: 350px;
-}
-.search-results .desc {
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
- display: block;
-}
-
-#help {
- background: #e9e9e9;
- border-radius: 4px;
- box-shadow: 0 0 6px rgba(0,0,0,.2);
-
- position: absolute;
- top: 300px;
- left: 50%;
- margin-top: -125px;
- margin-left: -275px;
- width: 550px;
- height: 250px;
- border: 1px solid #bfbfbf;
-}
-
-#help dt {
- float: left;
- border-radius: 3px;
- border: 1px solid #bfbfbf;
- background: #fff;
- width: 23px;
- text-align: center;
- clear: left;
- display: block;
- margin-top: -1px;
-}
-#help dd { margin: 5px 33px; }
-#help .infos { padding-left: 0; }
-#help h1 { margin-top: 0; }
-#help div {
- width: 50%;
- float: left;
- padding: 20px;
-}
+++ /dev/null
-// Copyright 2013 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.
-
-/*jslint browser: true, es5: true */
-/*globals $: true, searchIndex: true, rootPath: true, allPaths: true */
-
-(function () {
- "use strict";
- var resizeTimeout, interval;
-
- $('.js-only').removeClass('js-only');
-
- function resizeShortBlocks() {
- if (resizeTimeout) {
- clearTimeout(resizeTimeout);
- }
- resizeTimeout = setTimeout(function () {
- var contentWidth = $('.content').width();
- $('.docblock.short').width(function () {
- return contentWidth - 40 - $(this).prev().width();
- }).addClass('nowrap');
- }, 150);
- }
- resizeShortBlocks();
- $(window).on('resize', resizeShortBlocks);
-
- $(document).on('keyup', function (e) {
- if (document.activeElement.tagName === 'INPUT') {
- return;
- }
-
- if (e.keyCode === 188 && $('#help').hasClass('hidden')) { // question mark
- e.preventDefault();
- $('#help').removeClass('hidden');
- } else if (e.keyCode === 27 && !$('#help').hasClass('hidden')) { // esc
- e.preventDefault();
- $('#help').addClass('hidden');
- } else if (e.keyCode === 83) { // S
- e.preventDefault();
- $('.search-input').focus();
- }
- }).on('click', function (e) {
- if (!$(e.target).closest('#help').length) {
- $('#help').addClass('hidden');
- }
- });
-
- $('.version-selector').on('change', function () {
- var i, match,
- url = document.location.href,
- stripped = '',
- len = rootPath.match(/\.\.\//g).length + 1;
-
- for (i = 0; i < len; i += 1) {
- match = url.match(/\/[^\/]*$/);
- if (i < len - 1) {
- stripped = match[0] + stripped;
- }
- url = url.substring(0, url.length - match[0].length);
- }
-
- url += '/' + $('.version-selector').val() + stripped;
-
- document.location.href = url;
- });
-
- function initSearch(searchIndex) {
- var currentResults, index;
-
- // clear cached values from the search bar
- $(".search-input")[0].value = '';
-
- function execQuery(query, max, searchWords) {
- var valLower = query.query.toLowerCase(),
- val = valLower,
- typeFilter = query.type,
- results = [],
- aa = 0,
- bb = 0;
-
- // quoted values mean literal search
- bb = searchWords.length;
- if ((val.charAt(0) === "\"" || val.charAt(0) === "'") && val.charAt(val.length - 1) === val.charAt(0)) {
- val = val.substr(1, val.length - 2);
- for (aa = 0; aa < bb; aa += 1) {
- if (searchWords[aa] === val) {
- // filter type: ... queries
- if (!typeFilter || typeFilter === searchIndex[aa].ty) {
- results.push([aa, -1]);
- }
- }
- if (results.length === max) {
- break;
- }
- }
- } else {
- // gather matching search results up to a certain maximum
- val = val.replace(/\_/g, "");
- for (aa = 0; aa < bb; aa += 1) {
- if (searchWords[aa].indexOf(val) > -1 || searchWords[aa].replace(/_/g, "").indexOf(val) > -1) {
- // filter type: ... queries
- if (!typeFilter || typeFilter === searchIndex[aa].ty) {
- results.push([aa, searchWords[aa].replace(/_/g, "").indexOf(val)]);
- }
- }
- if (results.length === max) {
- break;
- }
- }
- }
- bb = results.length;
- for (aa = 0; aa < bb; aa += 1) {
- results[aa].push(searchIndex[results[aa][0]].ty);
- }
- for (aa = 0; aa < bb; aa += 1) {
- results[aa].push(searchIndex[results[aa][0]].path);
- }
-
- // if there are no results then return to default and fail
- if (results.length === 0) {
- return [];
- }
-
- // sort by exact match
- results.sort(function search_complete_sort0(aaa, bbb) {
- if (searchWords[aaa[0]] === valLower && searchWords[bbb[0]] !== valLower) {
- return 1;
- }
- });
- // first sorting attempt
- // sort by item name length
- results.sort(function search_complete_sort1(aaa, bbb) {
- if (searchWords[aaa[0]].length > searchWords[bbb[0]].length) {
- return 1;
- }
- });
- // second sorting attempt
- // sort by item name
- results.sort(function search_complete_sort1(aaa, bbb) {
- if (searchWords[aaa[0]].length === searchWords[bbb[0]].length && searchWords[aaa[0]] > searchWords[bbb[0]]) {
- return 1;
- }
- });
- // third sorting attempt
- // sort by index of keyword in item name
- if (results[0][1] !== -1) {
- results.sort(function search_complete_sort1(aaa, bbb) {
- if (aaa[1] > bbb[1] && bbb[1] === 0) {
- return 1;
- }
- });
- }
- // fourth sorting attempt
- // sort by type
- results.sort(function search_complete_sort3(aaa, bbb) {
- if (searchWords[aaa[0]] === searchWords[bbb[0]] && aaa[2] > bbb[2]) {
- return 1;
- }
- });
- // fifth sorting attempt
- // sort by path
- results.sort(function search_complete_sort4(aaa, bbb) {
- if (searchWords[aaa[0]] === searchWords[bbb[0]] && aaa[2] === bbb[2] && aaa[3] > bbb[3]) {
- return 1;
- }
- });
- // sixth sorting attempt
- // remove duplicates, according to the data provided
- for (aa = results.length - 1; aa > 0; aa -= 1) {
- if (searchWords[results[aa][0]] === searchWords[results[aa - 1][0]] && results[aa][2] === results[aa - 1][2] && results[aa][3] === results[aa - 1][3]) {
- results[aa][0] = -1;
- }
- }
-
- return results;
- }
-
- function getQuery() {
- var matches, type, query = $('.search-input').val();
-
- matches = query.match(/^(fn|mod|str(uct)?|enum|trait|t(ype)?d(ef)?)\s*:\s*/i);
- if (matches) {
- type = matches[1].replace(/^td$/, 'typedef').replace(/^str$/, 'struct').replace(/^tdef$/, 'typedef').replace(/^typed$/, 'typedef');
- query = query.substring(matches[0].length);
- }
-
- return {
- query: query,
- type: type,
- id: query + type,
- };
- }
-
- function initSearchNav() {
- var hoverTimeout, $results = $('.search-results .result');
-
- $results.on('click', function () {
- document.location.href = $(this).find('a').prop('href');
- }).on('mouseover', function () {
- var $el = $(this);
- clearTimeout(hoverTimeout);
- hoverTimeout = setTimeout(function () {
- $results.removeClass('highlighted');
- $el.addClass('highlighted');
- }, 20);
- });
-
- $(document).off('keyup.searchnav');
- $(document).on('keyup.searchnav', function (e) {
- var $active = $results.filter('.highlighted');
-
- if (e.keyCode === 38) { // up
- e.preventDefault();
- if (!$active.length || !$active.prev()) {
- return;
- }
-
- $active.prev().addClass('highlighted');
- $active.removeClass('highlighted');
- } else if (e.keyCode === 40) { // down
- e.preventDefault();
- if (!$active.length) {
- $results.first().addClass('highlighted');
- } else if ($active.next().length) {
- $active.next().addClass('highlighted');
- $active.removeClass('highlighted');
- }
- } else if (e.keyCode === 13) { // return
- e.preventDefault();
- if ($active.length) {
- document.location.href = $active.find('a').prop('href');
- }
- }
- });
- }
-
- function showResults(results) {
- var output, shown, query = getQuery();
-
- currentResults = query.id;
- output = '<h1>Results for ' + query.query + (query.type ? ' (type: ' + query.type + ')' : '') + '</h1>';
- output += '<table class="search-results">';
-
- if (results.length > 0) {
- shown = [];
-
- results.forEach(function (item) {
- var name, type;
-
- if (shown.indexOf(item) !== -1) {
- return;
- }
-
- shown.push(item);
- name = item.name;
- type = item.ty;
-
- output += '<tr class="' + type + ' result"><td>';
-
- if (type === 'mod') {
- output += item.path + '::<a href="' + rootPath + item.path.replace(/::/g, '/') + '/' + name + '/index.html" class="' + type + '">' + name + '</a>';
- } else if (type === 'static' || type === 'reexport') {
- output += item.path + '::<a href="' + rootPath + item.path.replace(/::/g, '/') + '/index.html" class="' + type + '">' + name + '</a>';
- } else if (item.parent !== undefined) {
- var myparent = allPaths[item.parent];
- output += item.path + '::' + myparent.name + '::<a href="' + rootPath + item.path.replace(/::/g, '/') + '/' + myparent.type + '.' + myparent.name + '.html" class="' + type + '">' + name + '</a>';
- } else {
- output += item.path + '::<a href="' + rootPath + item.path.replace(/::/g, '/') + '/' + type + '.' + name + '.html" class="' + type + '">' + name + '</a>';
- }
-
- output += '</td><td><span class="desc">' + item.desc + '</span></td></tr>';
- });
- } else {
- output += 'No results :( <a href="https://duckduckgo.com/?q=' + encodeURIComponent('rust ' + query.query) + '">Try on DuckDuckGo?</a>';
- }
-
- output += "</p>";
- $('.content').html(output);
- $('.search-results .desc').width($('.content').width() - 40 - $('.content td:first-child').first().width());
- initSearchNav();
- }
-
- function search(e) {
- var query, filterdata = [], obj, i, len,
- results = [],
- maxResults = 200,
- resultIndex;
-
- query = getQuery();
- if (e) {
- e.preventDefault();
- }
-
- if (!query.query || query.id === currentResults) {
- return;
- }
-
- resultIndex = execQuery(query, 20000, index);
- len = resultIndex.length;
- for (i = 0; i < len; i += 1) {
- if (resultIndex[i][0] > -1) {
- obj = searchIndex[resultIndex[i][0]];
- filterdata.push([obj.name, obj.ty, obj.path, obj.desc]);
- results.push(obj);
- }
- if (results.length >= maxResults) {
- break;
- }
- }
-
- // TODO add sorting capability through this function?
- //
- // // the handler for the table heading filtering
- // filterdraw = function search_complete_filterdraw(node) {
- // var name = "",
- // arrow = "",
- // op = 0,
- // tbody = node.parentNode.parentNode.nextSibling,
- // anchora = {},
- // tra = {},
- // tha = {},
- // td1a = {},
- // td2a = {},
- // td3a = {},
- // aaa = 0,
- // bbb = 0;
- //
- // // the 4 following conditions set the rules for each
- // // table heading
- // if (node === ths[0]) {
- // op = 0;
- // name = "name";
- // ths[1].innerHTML = ths[1].innerHTML.split(" ")[0];
- // ths[2].innerHTML = ths[2].innerHTML.split(" ")[0];
- // ths[3].innerHTML = ths[3].innerHTML.split(" ")[0];
- // }
- // if (node === ths[1]) {
- // op = 1;
- // name = "type";
- // ths[0].innerHTML = ths[0].innerHTML.split(" ")[0];
- // ths[2].innerHTML = ths[2].innerHTML.split(" ")[0];
- // ths[3].innerHTML = ths[3].innerHTML.split(" ")[0];
- // }
- // if (node === ths[2]) {
- // op = 2;
- // name = "path";
- // ths[0].innerHTML = ths[0].innerHTML.split(" ")[0];
- // ths[1].innerHTML = ths[1].innerHTML.split(" ")[0];
- // ths[3].innerHTML = ths[3].innerHTML.split(" ")[0];
- // }
- // if (node === ths[3]) {
- // op = 3;
- // name = "description";
- // ths[0].innerHTML = ths[0].innerHTML.split(" ")[0];
- // ths[1].innerHTML = ths[1].innerHTML.split(" ")[0];
- // ths[2].innerHTML = ths[2].innerHTML.split(" ")[0];
- // }
- //
- // // ascending or descending search
- // arrow = node.innerHTML.split(" ")[1];
- // if (arrow === undefined || arrow === "\u25b2") {
- // arrow = "\u25bc";
- // } else {
- // arrow = "\u25b2";
- // }
- //
- // // filter the data
- // filterdata.sort(function search_complete_filterDraw_sort(xx, yy) {
- // if ((arrow === "\u25b2" && xx[op].toLowerCase() < yy[op].toLowerCase()) || (arrow === "\u25bc" && xx[op].toLowerCase() > yy[op].toLowerCase())) {
- // return 1;
- // }
- // });
- // };
-
- showResults(results);
- }
-
- function buildIndex(searchIndex) {
- var len = searchIndex.length,
- i = 0,
- searchWords = [];
-
- // before any analysis is performed lets gather the search terms to
- // search against apart from the rest of the data. This is a quick
- // operation that is cached for the life of the page state so that
- // all other search operations have access to this cached data for
- // faster analysis operations
- for (i = 0; i < len; i += 1) {
- if (typeof searchIndex[i].name === "string") {
- searchWords.push(searchIndex[i].name.toLowerCase());
- } else {
- searchWords.push("");
- }
- }
-
- return searchWords;
- }
-
- function startSearch() {
- var keyUpTimeout;
- $('.do-search').on('click', search);
- $('.search-input').on('keyup', function () {
- clearTimeout(keyUpTimeout);
- keyUpTimeout = setTimeout(search, 100);
- });
- }
-
- index = buildIndex(searchIndex);
- startSearch();
- }
-
- initSearch(searchIndex);
-}());
+++ /dev/null
-/*! normalize.css v2.1.2 | MIT License | git.io/normalize */
-
-/* ==========================================================================
- HTML5 display definitions
- ========================================================================== */
-
-/**
- * Correct `block` display not defined in IE 8/9.
- */
-
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-nav,
-section,
-summary {
- display: block;
-}
-
-/**
- * Correct `inline-block` display not defined in IE 8/9.
- */
-
-audio,
-canvas,
-video {
- display: inline-block;
-}
-
-/**
- * Prevent modern browsers from displaying `audio` without controls.
- * Remove excess height in iOS 5 devices.
- */
-
-audio:not([controls]) {
- display: none;
- height: 0;
-}
-
-/**
- * Address styling not present in IE 8/9.
- */
-
-[hidden] {
- display: none;
-}
-
-/* ==========================================================================
- Base
- ========================================================================== */
-
-/**
- * 1. Set default font family to sans-serif.
- * 2. Prevent iOS text size adjust after orientation change, without disabling
- * user zoom.
- */
-
-html {
- font-family: sans-serif; /* 1 */
- -ms-text-size-adjust: 100%; /* 2 */
- -webkit-text-size-adjust: 100%; /* 2 */
-}
-
-/**
- * Remove default margin.
- */
-
-body {
- margin: 0;
-}
-
-/* ==========================================================================
- Links
- ========================================================================== */
-
-/**
- * Address `outline` inconsistency between Chrome and other browsers.
- */
-
-a:focus {
- outline: thin dotted;
-}
-
-/**
- * Improve readability when focused and also mouse hovered in all browsers.
- */
-
-a:active,
-a:hover {
- outline: 0;
-}
-
-/* ==========================================================================
- Typography
- ========================================================================== */
-
-/**
- * Address variable `h1` font-size and margin within `section` and `article`
- * contexts in Firefox 4+, Safari 5, and Chrome.
- */
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-/**
- * Address styling not present in IE 8/9, Safari 5, and Chrome.
- */
-
-abbr[title] {
- border-bottom: 1px dotted;
-}
-
-/**
- * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
- */
-
-b,
-strong {
- font-weight: bold;
-}
-
-/**
- * Address styling not present in Safari 5 and Chrome.
- */
-
-dfn {
- font-style: italic;
-}
-
-/**
- * Address differences between Firefox and other browsers.
- */
-
-hr {
- -moz-box-sizing: content-box;
- box-sizing: content-box;
- height: 0;
-}
-
-/**
- * Address styling not present in IE 8/9.
- */
-
-mark {
- background: #ff0;
- color: #000;
-}
-
-/**
- * Correct font family set oddly in Safari 5 and Chrome.
- */
-
-code,
-kbd,
-pre,
-samp {
- font-family: monospace, serif;
- font-size: 1em;
-}
-
-/**
- * Improve readability of pre-formatted text in all browsers.
- */
-
-pre {
- white-space: pre-wrap;
-}
-
-/**
- * Set consistent quote types.
- */
-
-q {
- quotes: "\201C" "\201D" "\2018" "\2019";
-}
-
-/**
- * Address inconsistent and variable font size in all browsers.
- */
-
-small {
- font-size: 80%;
-}
-
-/**
- * Prevent `sub` and `sup` affecting `line-height` in all browsers.
- */
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sup {
- top: -0.5em;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-/* ==========================================================================
- Embedded content
- ========================================================================== */
-
-/**
- * Remove border when inside `a` element in IE 8/9.
- */
-
-img {
- border: 0;
-}
-
-/**
- * Correct overflow displayed oddly in IE 9.
- */
-
-svg:not(:root) {
- overflow: hidden;
-}
-
-/* ==========================================================================
- Figures
- ========================================================================== */
-
-/**
- * Address margin not present in IE 8/9 and Safari 5.
- */
-
-figure {
- margin: 0;
-}
-
-/* ==========================================================================
- Forms
- ========================================================================== */
-
-/**
- * Define consistent border, margin, and padding.
- */
-
-fieldset {
- border: 1px solid #c0c0c0;
- margin: 0 2px;
- padding: 0.35em 0.625em 0.75em;
-}
-
-/**
- * 1. Correct `color` not being inherited in IE 8/9.
- * 2. Remove padding so people aren't caught out if they zero out fieldsets.
- */
-
-legend {
- border: 0; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * 1. Correct font family not being inherited in all browsers.
- * 2. Correct font size not being inherited in all browsers.
- * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
- */
-
-button,
-input,
-select,
-textarea {
- font-family: inherit; /* 1 */
- font-size: 100%; /* 2 */
- margin: 0; /* 3 */
-}
-
-/**
- * Address Firefox 4+ setting `line-height` on `input` using `!important` in
- * the UA stylesheet.
- */
-
-button,
-input {
- line-height: normal;
-}
-
-/**
- * Address inconsistent `text-transform` inheritance for `button` and `select`.
- * All other form control elements do not inherit `text-transform` values.
- * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
- * Correct `select` style inheritance in Firefox 4+ and Opera.
- */
-
-button,
-select {
- text-transform: none;
-}
-
-/**
- * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
- * and `video` controls.
- * 2. Correct inability to style clickable `input` types in iOS.
- * 3. Improve usability and consistency of cursor style between image-type
- * `input` and others.
- */
-
-button,
-html input[type="button"], /* 1 */
-input[type="reset"],
-input[type="submit"] {
- -webkit-appearance: button; /* 2 */
- cursor: pointer; /* 3 */
-}
-
-/**
- * Re-set default cursor for disabled elements.
- */
-
-button[disabled],
-html input[disabled] {
- cursor: default;
-}
-
-/**
- * 1. Address box sizing set to `content-box` in IE 8/9.
- * 2. Remove excess padding in IE 8/9.
- */
-
-input[type="checkbox"],
-input[type="radio"] {
- box-sizing: border-box; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
- * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
- * (include `-moz` to future-proof).
- */
-
-input[type="search"] {
- -webkit-appearance: textfield; /* 1 */
- -moz-box-sizing: content-box;
- -webkit-box-sizing: content-box; /* 2 */
- box-sizing: content-box;
-}
-
-/**
- * Remove inner padding and search cancel button in Safari 5 and Chrome
- * on OS X.
- */
-
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-/**
- * Remove inner padding and border in Firefox 4+.
- */
-
-button::-moz-focus-inner,
-input::-moz-focus-inner {
- border: 0;
- padding: 0;
-}
-
-/**
- * 1. Remove default vertical scrollbar in IE 8/9.
- * 2. Improve readability and alignment in all browsers.
- */
-
-textarea {
- overflow: auto; /* 1 */
- vertical-align: top; /* 2 */
-}
-
-/* ==========================================================================
- Tables
- ========================================================================== */
-
-/**
- * Remove most spacing between table cells.
- */
-
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::num;
-use std::uint;
-
-use clean;
-use syntax::ast;
-use clean::Item;
-use plugins;
-use fold;
-use fold::DocFolder;
-
-/// Strip items marked `#[doc(hidden)]`
-pub fn strip_hidden(crate: clean::Crate) -> plugins::PluginResult {
- struct Stripper;
- impl fold::DocFolder for Stripper {
- fn fold_item(&mut self, i: Item) -> Option<Item> {
- for attr in i.attrs.iter() {
- match attr {
- &clean::List(~"doc", ref l) => {
- for innerattr in l.iter() {
- match innerattr {
- &clean::Word(ref s) if "hidden" == *s => {
- debug!("found one in strip_hidden; removing");
- return None;
- },
- _ => (),
- }
- }
- },
- _ => ()
- }
- }
- self.fold_item_recur(i)
- }
- }
- let mut stripper = Stripper;
- let crate = stripper.fold_crate(crate);
- (crate, None)
-}
-
-pub fn unindent_comments(crate: clean::Crate) -> plugins::PluginResult {
- struct CommentCleaner;
- impl fold::DocFolder for CommentCleaner {
- fn fold_item(&mut self, i: Item) -> Option<Item> {
- let mut i = i;
- let mut avec: ~[clean::Attribute] = ~[];
- for attr in i.attrs.iter() {
- match attr {
- &clean::NameValue(~"doc", ref s) => avec.push(
- clean::NameValue(~"doc", unindent(*s))),
- x => avec.push(x.clone())
- }
- }
- i.attrs = avec;
- self.fold_item_recur(i)
- }
- }
- let mut cleaner = CommentCleaner;
- let crate = cleaner.fold_crate(crate);
- (crate, None)
-}
-
-pub fn collapse_privacy(crate: clean::Crate) -> plugins::PluginResult {
- struct PrivacyCollapser {
- stack: ~[clean::Visibility]
- }
- impl fold::DocFolder for PrivacyCollapser {
- fn fold_item(&mut self, mut i: Item) -> Option<Item> {
- if i.visibility.is_some() {
- if i.visibility == Some(ast::inherited) {
- i.visibility = Some(self.stack.last().clone());
- } else {
- self.stack.push(i.visibility.clone().unwrap());
- }
- }
- self.fold_item_recur(i)
- }
- }
- let mut privacy = PrivacyCollapser { stack: ~[] };
- let crate = privacy.fold_crate(crate);
- (crate, None)
-}
-
-pub fn collapse_docs(crate: clean::Crate) -> plugins::PluginResult {
- struct Collapser;
- impl fold::DocFolder for Collapser {
- fn fold_item(&mut self, i: Item) -> Option<Item> {
- let mut docstr = ~"";
- let mut i = i;
- for attr in i.attrs.iter() {
- match *attr {
- clean::NameValue(~"doc", ref s) => {
- docstr.push_str(s.clone());
- docstr.push_char('\n');
- },
- _ => ()
- }
- }
- let mut a: ~[clean::Attribute] = i.attrs.iter().filter(|&a| match a {
- &clean::NameValue(~"doc", _) => false,
- _ => true
- }).map(|x| x.clone()).collect();
- if "" != docstr {
- a.push(clean::NameValue(~"doc", docstr.trim().to_owned()));
- }
- i.attrs = a;
- self.fold_item_recur(i)
- }
- }
- let mut collapser = Collapser;
- let crate = collapser.fold_crate(crate);
- (crate, None)
-}
-
-// n.b. this is copied from src/librustdoc/unindent_pass.rs
-pub fn unindent(s: &str) -> ~str {
- let lines = s.any_line_iter().collect::<~[&str]>();
- let mut saw_first_line = false;
- let mut saw_second_line = false;
- let min_indent = do lines.iter().fold(uint::max_value) |min_indent, line| {
-
- // After we see the first non-whitespace line, look at
- // the line we have. If it is not whitespace, and therefore
- // part of the first paragraph, then ignore the indentation
- // level of the first line
- let ignore_previous_indents =
- saw_first_line &&
- !saw_second_line &&
- !line.is_whitespace();
-
- let min_indent = if ignore_previous_indents {
- uint::max_value
- } else {
- min_indent
- };
-
- if saw_first_line {
- saw_second_line = true;
- }
-
- if line.is_whitespace() {
- min_indent
- } else {
- saw_first_line = true;
- let mut spaces = 0;
- do line.iter().all |char| {
- // Only comparing against space because I wouldn't
- // know what to do with mixed whitespace chars
- if char == ' ' {
- spaces += 1;
- true
- } else {
- false
- }
- };
- num::min(min_indent, spaces)
- }
- };
-
- match lines {
- [head, .. tail] => {
- let mut unindented = ~[ head.trim() ];
- unindented.push_all(do tail.map |&line| {
- if line.is_whitespace() {
- line
- } else {
- assert!(line.len() >= min_indent);
- line.slice_from(min_indent)
- }
- });
- unindented.connect("\n")
- }
- [] => s.to_owned()
- }
-}
-
-#[cfg(test)]
-mod unindent_tests {
- use super::unindent;
-
- #[test]
- fn should_unindent() {
- let s = ~" line1\n line2";
- let r = unindent(s);
- assert_eq!(r, ~"line1\nline2");
- }
-
- #[test]
- fn should_unindent_multiple_paragraphs() {
- let s = ~" line1\n\n line2";
- let r = unindent(s);
- assert_eq!(r, ~"line1\n\nline2");
- }
-
- #[test]
- fn should_leave_multiple_indent_levels() {
- // Line 2 is indented another level beyond the
- // base indentation and should be preserved
- let s = ~" line1\n\n line2";
- let r = unindent(s);
- assert_eq!(r, ~"line1\n\n line2");
- }
-
- #[test]
- fn should_ignore_first_line_indent() {
- // Thi first line of the first paragraph may not be indented as
- // far due to the way the doc string was written:
- //
- // #[doc = "Start way over here
- // and continue here"]
- let s = ~"line1\n line2";
- let r = unindent(s);
- assert_eq!(r, ~"line1\nline2");
- }
-
- #[test]
- fn should_not_ignore_first_line_indent_in_a_single_line_para() {
- let s = ~"line1\n\n line2";
- let r = unindent(s);
- assert_eq!(r, ~"line1\n\n line2");
- }
-}
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use clean;
-
-use extra;
-use dl = std::unstable::dynamic_lib;
-
-pub type PluginJson = Option<(~str, extra::json::Json)>;
-pub type PluginResult = (clean::Crate, PluginJson);
-pub type plugin_callback = extern fn (clean::Crate) -> PluginResult;
-
-/// Manages loading and running of plugins
-pub struct PluginManager {
- priv dylibs: ~[dl::DynamicLibrary],
- priv callbacks: ~[plugin_callback],
- /// The directory plugins will be loaded from
- prefix: Path,
-}
-
-impl PluginManager {
- /// Create a new plugin manager
- pub fn new(prefix: Path) -> PluginManager {
- PluginManager {
- dylibs: ~[],
- callbacks: ~[],
- prefix: prefix,
- }
- }
-
- /// Load a plugin with the given name.
- ///
- /// Turns `name` into the proper dynamic library filename for the given
- /// platform. On windows, it turns into name.dll, on OS X, name.dylib, and
- /// elsewhere, libname.so.
- pub fn load_plugin(&mut self, name: ~str) {
- let x = self.prefix.push(libname(name));
- let lib_result = dl::DynamicLibrary::open(Some(&x));
- let lib = lib_result.unwrap();
- let plugin = unsafe { lib.symbol("rustdoc_plugin_entrypoint") }.unwrap();
- self.dylibs.push(lib);
- self.callbacks.push(plugin);
- }
-
- /// Load a normal Rust function as a plugin.
- ///
- /// This is to run passes over the cleaned crate. Plugins run this way
- /// correspond to the A-aux tag on Github.
- pub fn add_plugin(&mut self, plugin: plugin_callback) {
- self.callbacks.push(plugin);
- }
- /// Run all the loaded plugins over the crate, returning their results
- pub fn run_plugins(&self, crate: clean::Crate) -> (clean::Crate, ~[PluginJson]) {
- let mut out_json = ~[];
- let mut crate = crate;
- for &callback in self.callbacks.iter() {
- let (c, res) = callback(crate);
- crate = c;
- out_json.push(res);
- }
- (crate, out_json)
- }
-}
-
-#[cfg(target_os="win32")]
-fn libname(mut n: ~str) -> ~str {
- n.push_str(".dll");
- n
-}
-
-#[cfg(target_os="macos")]
-fn libname(mut n: ~str) -> ~str {
- n.push_str(".dylib");
- n
-}
-
-#[cfg(not(target_os="win32"), not(target_os="macos"))]
-fn libname(n: ~str) -> ~str {
- let mut i = ~"lib";
- i.push_str(n);
- i.push_str(".so");
- i
-}
+++ /dev/null
-// Copyright 2012-2013 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.
-
-#[link(name = "rustdoc_ng",
- vers = "0.8-pre",
- uuid = "8c6e4598-1596-4aa5-a24c-b811914bbbc6",
- url = "https://github.com/mozilla/rust/tree/master/src/rustdoc_ng")];
-
-#[desc = "rustdoc, the Rust documentation extractor"];
-#[license = "MIT/ASL2"];
-#[crate_type = "lib"];
-
-extern mod syntax;
-extern mod rustc;
-extern mod extra;
-
-use extra::serialize::Encodable;
-use extra::time;
-use std::cell::Cell;
-use std::rt::io;
-use std::rt::io::Writer;
-use std::rt::io::file::FileInfo;
-
-pub mod clean;
-pub mod core;
-pub mod doctree;
-pub mod fold;
-pub mod html {
- pub mod render;
- pub mod layout;
- pub mod markdown;
- pub mod format;
-}
-pub mod passes;
-pub mod plugins;
-pub mod visit_ast;
-
-pub static SCHEMA_VERSION: &'static str = "0.8.0";
-
-local_data_key!(pub ctxtkey: @core::DocContext)
-
-enum OutputFormat {
- HTML, JSON
-}
-
-pub fn main() {
- main_args(std::os::args());
-}
-
-pub fn main_args(args: &[~str]) {
- use extra::getopts::groups::*;
-
- let opts = ~[
- optmulti("L", "library-path", "directory to add to crate search path",
- "DIR"),
- optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
- optmulti("", "passes", "space separated list of passes to also run",
- "PASSES"),
- optmulti("", "plugins", "space separated list of plugins to also load",
- "PLUGINS"),
- optflag("h", "help", "show this help message"),
- optflag("", "nodefaults", "don't run the default passes"),
- optopt("o", "output", "where to place the output", "PATH"),
- ];
-
- let matches = getopts(args.tail(), opts).unwrap();
-
- let myusage = || {
- println(usage(format!("{} [options] [html|json] <crate>", args[0]), opts));
- };
-
- if matches.opt_present("h") || matches.opt_present("help") {
- myusage();
- return;
- }
-
- let (format, cratefile) = match matches.free.clone() {
- [~"json", crate] => (JSON, crate),
- [~"html", crate] => (HTML, crate),
- [s, _] => {
- println!("Unknown output format: `{}`", s);
- myusage();
- exit(1);
- }
- [_, .._] => {
- println!("Expected exactly one crate to process");
- myusage();
- exit(1);
- }
- _ => {
- println!("Expected an output format and then one crate");
- myusage();
- exit(1);
- }
- };
-
- // First, parse the crate and extract all relevant information.
- let libs = Cell::new(matches.opt_strs("L").map(|s| Path(*s)));
- let cr = Cell::new(Path(cratefile));
- info2!("starting to run rustc");
- let crate = do std::task::try {
- let cr = cr.take();
- core::run_core(libs.take(), &cr)
- }.unwrap();
- info2!("finished with rustc");
-
- // Process all of the crate attributes, extracting plugin metadata along
- // with the passes which we are supposed to run.
- let mut default_passes = !matches.opt_present("nodefaults");
- let mut passes = matches.opt_strs("passes");
- let mut plugins = matches.opt_strs("plugins");
- match crate.module.get_ref().doc_list() {
- Some(nested) => {
- for inner in nested.iter() {
- match *inner {
- clean::Word(~"no_default_passes") => {
- default_passes = false;
- }
- clean::NameValue(~"passes", ref value) => {
- for pass in value.word_iter() {
- passes.push(pass.to_owned());
- }
- }
- clean::NameValue(~"plugins", ref value) => {
- for p in value.word_iter() {
- plugins.push(p.to_owned());
- }
- }
- _ => {}
- }
- }
- }
- None => {}
- }
- if default_passes {
- passes.unshift(~"collapse-docs");
- passes.unshift(~"unindent-comments");
- }
-
- // Load all plugins/passes into a PluginManager
- let mut pm = plugins::PluginManager::new(Path("/tmp/rustdoc_ng/plugins"));
- for pass in passes.iter() {
- let plugin = match pass.as_slice() {
- "strip-hidden" => passes::strip_hidden,
- "unindent-comments" => passes::unindent_comments,
- "collapse-docs" => passes::collapse_docs,
- "collapse-privacy" => passes::collapse_privacy,
- s => { error!("unknown pass %s, skipping", s); loop },
- };
- pm.add_plugin(plugin);
- }
- info2!("loading plugins...");
- for pname in plugins.move_iter() {
- pm.load_plugin(pname);
- }
-
- // Run everything!
- info2!("Executing passes/plugins");
- let (crate, res) = pm.run_plugins(crate);
-
- info2!("going to format");
- let started = time::precise_time_ns();
- let output = matches.opt_str("o").map(|s| Path(*s));
- match format {
- HTML => { html::render::run(crate, output.unwrap_or(Path("doc"))) }
- JSON => { jsonify(crate, res, output.unwrap_or(Path("doc.json"))) }
- }
- let ended = time::precise_time_ns();
- info2!("Took {:.03f}s", (ended as f64 - started as f64) / 1000000000f64);
-}
-
-fn jsonify(crate: clean::Crate, res: ~[plugins::PluginJson], dst: Path) {
- // {
- // "schema": version,
- // "crate": { parsed crate ... },
- // "plugins": { output of plugins ... }
- // }
- let mut json = ~extra::treemap::TreeMap::new();
- json.insert(~"schema", extra::json::String(SCHEMA_VERSION.to_owned()));
- let plugins_json = ~res.move_iter().filter_map(|opt| opt).collect();
-
- // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
- // straight to the Rust JSON representation.
- let crate_json_str = do std::io::with_str_writer |w| {
- crate.encode(&mut extra::json::Encoder(w));
- };
- let crate_json = match extra::json::from_str(crate_json_str) {
- Ok(j) => j,
- Err(_) => fail!("Rust generated JSON is invalid??")
- };
-
- json.insert(~"crate", crate_json);
- json.insert(~"plugins", extra::json::Object(plugins_json));
-
- let mut file = dst.open_writer(io::Create).unwrap();
- let output = extra::json::Object(json).to_str();
- file.write(output.as_bytes());
-}
-
-fn exit(status: int) -> ! {
- #[fixed_stack_segment]; #[inline(never)];
- use std::libc;
- unsafe { libc::exit(status as libc::c_int) }
-}
+++ /dev/null
-// Copyright 2012-2013 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.
-
-//! Rust AST Visitor. Extracts useful information and massages it into a form
-//! usable for clean
-
-use syntax::abi::AbiSet;
-use syntax::{ast, ast_map};
-use syntax::codemap::Span;
-
-use doctree::*;
-use std::local_data;
-
-pub struct RustdocVisitor {
- module: Module,
- attrs: ~[ast::Attribute],
-}
-
-impl RustdocVisitor {
- pub fn new() -> RustdocVisitor {
- RustdocVisitor {
- module: Module::new(None),
- attrs: ~[],
- }
- }
-}
-
-impl RustdocVisitor {
- pub fn visit(@mut self, crate: &ast::Crate) {
- self.attrs = crate.attrs.clone();
- fn visit_struct_def(item: &ast::item, sd: @ast::struct_def, generics:
- &ast::Generics) -> Struct {
- debug!("Visiting struct");
- let struct_type = struct_type_from_def(sd);
- Struct {
- id: item.id,
- struct_type: struct_type,
- name: item.ident,
- vis: item.vis,
- attrs: item.attrs.clone(),
- generics: generics.clone(),
- fields: sd.fields.iter().map(|x| (*x).clone()).to_owned_vec(),
- where: item.span
- }
- }
-
- fn visit_enum_def(it: &ast::item, def: &ast::enum_def, params: &ast::Generics) -> Enum {
- debug!("Visiting enum");
- let mut vars: ~[Variant] = ~[];
- for x in def.variants.iter() {
- vars.push(Variant {
- name: x.node.name,
- attrs: x.node.attrs.clone(),
- vis: x.node.vis,
- id: x.node.id,
- kind: x.node.kind.clone(),
- where: x.span,
- });
- }
- Enum {
- name: it.ident,
- variants: vars,
- vis: it.vis,
- generics: params.clone(),
- attrs: it.attrs.clone(),
- id: it.id,
- where: it.span,
- }
- }
-
- fn visit_fn(item: &ast::item, fd: &ast::fn_decl, _purity: &ast::purity,
- _abi: &AbiSet, gen: &ast::Generics) -> Function {
- debug!("Visiting fn");
- Function {
- id: item.id,
- vis: item.vis,
- attrs: item.attrs.clone(),
- decl: fd.clone(),
- name: item.ident,
- where: item.span,
- generics: gen.clone(),
- }
- }
-
- fn visit_mod_contents(span: Span, attrs: ~[ast::Attribute], vis:
- ast::visibility, id: ast::NodeId, m: &ast::_mod) -> Module {
- let am = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.items;
- let name = match am.find(&id) {
- Some(m) => match m {
- &ast_map::node_item(ref it, _) => Some(it.ident),
- _ => fail!("mod id mapped to non-item in the ast map")
- },
- None => None
- };
- let mut om = Module::new(name);
- om.view_items = m.view_items.clone();
- om.where = span;
- om.attrs = attrs;
- om.vis = vis;
- om.id = id;
- for i in m.items.iter() {
- visit_item(*i, &mut om);
- }
- om
- }
-
- fn visit_item(item: &ast::item, om: &mut Module) {
- debug!("Visiting item %?", item);
- match item.node {
- ast::item_mod(ref m) => {
- om.mods.push(visit_mod_contents(item.span, item.attrs.clone(),
- item.vis, item.id, m));
- },
- ast::item_enum(ref ed, ref gen) => om.enums.push(visit_enum_def(item, ed, gen)),
- ast::item_struct(sd, ref gen) => om.structs.push(visit_struct_def(item, sd, gen)),
- ast::item_fn(ref fd, ref pur, ref abi, ref gen, _) =>
- om.fns.push(visit_fn(item, fd, pur, abi, gen)),
- ast::item_ty(ref ty, ref gen) => {
- let t = Typedef {
- ty: ty.clone(),
- gen: gen.clone(),
- name: item.ident,
- id: item.id,
- attrs: item.attrs.clone(),
- where: item.span,
- vis: item.vis,
- };
- om.typedefs.push(t);
- },
- ast::item_static(ref ty, ref mut_, ref exp) => {
- let s = Static {
- type_: ty.clone(),
- mutability: mut_.clone(),
- expr: exp.clone(),
- id: item.id,
- name: item.ident,
- attrs: item.attrs.clone(),
- where: item.span,
- vis: item.vis,
- };
- om.statics.push(s);
- },
- ast::item_trait(ref gen, ref tr, ref met) => {
- let t = Trait {
- name: item.ident,
- methods: met.clone(),
- generics: gen.clone(),
- parents: tr.clone(),
- id: item.id,
- attrs: item.attrs.clone(),
- where: item.span,
- vis: item.vis,
- };
- om.traits.push(t);
- },
- ast::item_impl(ref gen, ref tr, ref ty, ref meths) => {
- let i = Impl {
- generics: gen.clone(),
- trait_: tr.clone(),
- for_: ty.clone(),
- methods: meths.clone(),
- attrs: item.attrs.clone(),
- id: item.id,
- where: item.span,
- vis: item.vis,
- };
- om.impls.push(i);
- },
- _ => (),
- }
- }
-
- self.module = visit_mod_contents(crate.span, crate.attrs.clone(),
- ast::public, ast::CRATE_NODE_ID, &crate.module);
- }
-}
use extra::time::precise_time_s;
use std::io;
use std::os;
-use std::rand::RngUtil;
+use std::rand::Rng;
use std::rand;
use std::str;
use std::util;
let mut v = ~[];
let mut i = 0;
while i < 1500 {
- let rv = vec::from_elem(r.gen_uint_range(0, i + 1), i);
+ let rv = vec::from_elem(r.gen_integer_range(0u, i + 1), i);
if r.gen() {
v.push_all_move(rv);
} else {
let mut v = ~[];
let mut i = 0;
while i < 1500 {
- let rv = vec::from_elem(r.gen_uint_range(0, i + 1), i);
+ let rv = vec::from_elem(r.gen_integer_range(0u, i + 1), i);
if r.gen() {
v = vec::append(v, rv);
}
let mut v = ~[];
for i in range(0u, 1500) {
- let mut rv = vec::from_elem(r.gen_uint_range(0, i + 1), i);
+ let mut rv = vec::from_elem(r.gen_integer_range(0u, i + 1), i);
if r.gen() {
v.push_all(rv);
}
// Perlin noise benchmark from https://gist.github.com/1170424
use std::float;
-use std::rand::{Rng, RngUtil};
+use std::rand::Rng;
use std::rand;
struct Vec2 {
#[no_std];
extern mod std;
extern mod zed(name = "std");
-extern mod bar(name = "std", vers = "0.8-pre");
+extern mod bar(name = "std", vers = "0.8");
use std::str;