auto merge of #13006 : alexcrichton/rust/rollup, r=alexcrichton

Closes #13008 (Made the `clone_from` implementation for `~T` reuse the `T` itself if possible)
Closes #13003 (Make method Vec::remove() public)
Closes #13002 (disallow duplicate methods in trait impls)
Closes #13000 (rustc: test: don't silently ignore bad benches)
Closes #12999 (rustc: buffer the output writer for -Z ast-json[-noexpand].)
Closes #12993 (syntax: Don't parameterize the the pretty printer)
Closes #12990 (`char` reference: s/character/Unicode scalar value/)
Closes #12987 (Move syntax-extension-hexfloat.rs)
Closes #12983 (Fix linkage1 test which fails due to --as-needed)
Closes #12978 (rustc: remove linker_private/linker_private_weak)
Closes #12976 (libsyntax: librustdoc: ignore utf-8 BOM in .rs files)
Closes #12973 (closes #12967 fix [en|de]coding of HashMap<K,V> where K is a numeric type)
Closes #12972 (Add impl IntoStr for ::std::vec_ng::Vec<Ascii>)
Closes #12968 (deny missing docs getopts)
Closes #12965 (Documentation and formatting changes for option.rs.)
Closes #12962 (Relax the memory ordering on the implementation of UnsafeArc)
Closes #12958 (Typo fixes.)
Closes #12950 (Docsprint: Document ops module, primarily Deref.)
Closes #12946 (rustdoc: Implement cross-crate searching)
This commit is contained in:
bors 2014-03-18 18:22:23 -07:00
commit 87e72c3812
33 changed files with 783 additions and 237 deletions

View File

@ -3136,8 +3136,12 @@ machine.
The types `char` and `str` hold textual data.
A value of type `char` is a Unicode character,
represented as a 32-bit unsigned word holding a UCS-4 codepoint.
A value of type `char` is a [Unicode scalar value](
http://www.unicode.org/glossary/#unicode_scalar_value)
(ie. a code point that is not a surrogate),
represented as a 32-bit unsigned word in the 0x0000 to 0xD7FF
or 0xE000 to 0x10FFFF range.
A `[char]` vector is effectively an UCS-4 / UTF-32 string.
A value of type `str` is a Unicode string,
represented as a vector of 8-bit unsigned bytes holding a sequence of UTF-8 codepoints.

View File

@ -43,7 +43,7 @@ pub fn recalibrate() {
Doc comments are markdown, and are currently parsed with the
[sundown][sundown] library. rustdoc does not yet do any fanciness such as
referencing other items inline, like javadoc's `@see`. One exception to this
is that the first paragrah will be used as the "summary" of an item in the
is that the first paragraph will be used as the "summary" of an item in the
generated documentation:
~~~
@ -79,11 +79,11 @@ rustdoc can also generate JSON, for consumption by other tools, with
# Using the Documentation
The web pages generated by rustdoc present the same logical heirarchy that one
The web pages generated by rustdoc present the same logical hierarchy that one
writes a library with. Every kind of item (function, struct, etc) has its own
color, and one can always click on a colored type to jump to its
documentation. There is a search bar at the top, which is powered by some
javascript and a statically-generated search index. No special web server is
JavaScript and a statically-generated search index. No special web server is
required for the search.
[sundown]: https://github.com/vmg/sundown/
@ -108,7 +108,7 @@ code, the `ignore` string can be added to the three-backtick form of markdown
code block.
/**
# nested codefences confuse sundown => indentation + comment to
# nested code fences confuse sundown => indentation + comment to
# avoid failing tests
```
// This is a testable code block
@ -126,7 +126,7 @@ You can specify that the test's execution should fail with the `should_fail`
directive.
/**
# nested codefences confuse sundown => indentation + comment to
# nested code fences confuse sundown => indentation + comment to
# avoid failing tests
```should_fail
// This code block is expected to generate a failure when run
@ -138,7 +138,7 @@ You can specify that the code block should be compiled but not run with the
`no_run` directive.
/**
# nested codefences confuse sundown => indentation + comment to
# nested code fences confuse sundown => indentation + comment to
# avoid failing tests
```no_run
// This code will be compiled but not executed
@ -153,7 +153,7 @@ testing the code block (NB. the space after the `#` is required, so
that one can still write things like `#[deriving(Eq)]`).
/**
# nested codefences confuse sundown => indentation + comment to
# nested code fences confuse sundown => indentation + comment to
# avoid failing tests
```rust
# /!\ The three following lines are comments, which are usually stripped off by
@ -162,7 +162,7 @@ that one can still write things like `#[deriving(Eq)]`).
# these first five lines but a non breakable one.
#
# // showing 'fib' in this documentation would just be tedious and detracts from
# // what's actualy being documented.
# // what's actually being documented.
# fn fib(n: int) { n + 2 }
do spawn { fib(200); }
@ -190,7 +190,7 @@ $ rustdoc --test lib.rs --test-args '--help'
~~~
When testing a library, code examples will often show how functions are used,
and this code often requires `use`-ing paths from the crate. To accomodate this,
and this code often requires `use`-ing paths from the crate. To accommodate this,
rustdoc will implicitly add `extern crate <crate>;` where `<crate>` is the name of
the crate being tested to the top of each code example. This means that rustdoc
must be able to find a compiled version of the library crate being tested. Extra

View File

@ -83,7 +83,7 @@
#[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://static.rust-lang.org/doc/master")];
#[allow(missing_doc)];
#[deny(missing_doc)];
#[allow(deprecated_owned_vector)];
#[feature(globs, phase)];

View File

@ -186,7 +186,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
});
if sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0 {
let mut stdout = io::stdout();
let mut stdout = io::BufferedWriter::new(io::stdout());
let mut json = json::PrettyEncoder::new(&mut stdout);
krate.encode(&mut json);
}
@ -261,7 +261,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
front::assign_node_ids_and_map::assign_node_ids_and_map(sess, krate));
if sess.opts.debugging_opts & session::AST_JSON != 0 {
let mut stdout = io::stdout();
let mut stdout = io::BufferedWriter::new(io::stdout());
let mut json = json::PrettyEncoder::new(&mut stdout);
krate.encode(&mut json);
}
@ -596,7 +596,7 @@ struct IdentifiedAnnotation;
impl pprust::PpAnn for IdentifiedAnnotation {
fn pre(&self,
s: &mut pprust::State<IdentifiedAnnotation>,
s: &mut pprust::State,
node: pprust::AnnNode) -> io::IoResult<()> {
match node {
pprust::NodeExpr(_) => s.popen(),
@ -604,7 +604,7 @@ impl pprust::PpAnn for IdentifiedAnnotation {
}
}
fn post(&self,
s: &mut pprust::State<IdentifiedAnnotation>,
s: &mut pprust::State,
node: pprust::AnnNode) -> io::IoResult<()> {
match node {
pprust::NodeItem(item) => {
@ -634,7 +634,7 @@ struct TypedAnnotation {
impl pprust::PpAnn for TypedAnnotation {
fn pre(&self,
s: &mut pprust::State<TypedAnnotation>,
s: &mut pprust::State,
node: pprust::AnnNode) -> io::IoResult<()> {
match node {
pprust::NodeExpr(_) => s.popen(),
@ -642,7 +642,7 @@ impl pprust::PpAnn for TypedAnnotation {
}
}
fn post(&self,
s: &mut pprust::State<TypedAnnotation>,
s: &mut pprust::State,
node: pprust::AnnNode) -> io::IoResult<()> {
let tcx = &self.analysis.ty_cx;
match node {

View File

@ -95,10 +95,9 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
debug!("current path: {}",
ast_util::path_name_i(self.cx.path.get().as_slice()));
if is_test_fn(&self.cx, i) || is_bench_fn(i) {
if is_test_fn(&self.cx, i) || is_bench_fn(&self.cx, i) {
match i.node {
ast::ItemFn(_, purity, _, _, _)
if purity == ast::UnsafeFn => {
ast::ItemFn(_, ast::UnsafeFn, _, _, _) => {
let sess = self.cx.sess;
sess.span_fatal(i.span,
"unsafe functions cannot be used for \
@ -109,7 +108,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
let test = Test {
span: i.span,
path: self.cx.path.get(),
bench: is_bench_fn(i),
bench: is_bench_fn(&self.cx, i),
ignore: is_ignored(&self.cx, i),
should_fail: should_fail(i)
};
@ -233,7 +232,7 @@ fn is_test_fn(cx: &TestCtxt, i: @ast::Item) -> bool {
return has_test_attr && has_test_signature(i);
}
fn is_bench_fn(i: @ast::Item) -> bool {
fn is_bench_fn(cx: &TestCtxt, i: @ast::Item) -> bool {
let has_bench_attr = attr::contains_name(i.attrs.as_slice(), "bench");
fn has_test_signature(i: @ast::Item) -> bool {
@ -254,6 +253,12 @@ fn is_bench_fn(i: @ast::Item) -> bool {
}
}
if has_bench_attr && !has_test_signature(i) {
let sess = cx.sess;
sess.span_err(i.span, "functions used as benches must have signature \
`fn(&mut BenchHarness) -> ()`");
}
return has_bench_attr && has_test_signature(i);
}

View File

@ -43,24 +43,22 @@ pub enum Visibility {
ProtectedVisibility = 2,
}
// This enum omits the obsolete (and no-op) linkage types DLLImportLinkage,
// DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage.
// LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either;
// they've been removed in upstream LLVM commit r203866.
pub enum Linkage {
ExternalLinkage = 0,
AvailableExternallyLinkage = 1,
LinkOnceAnyLinkage = 2,
LinkOnceODRLinkage = 3,
LinkOnceODRAutoHideLinkage = 4,
WeakAnyLinkage = 5,
WeakODRLinkage = 6,
AppendingLinkage = 7,
InternalLinkage = 8,
PrivateLinkage = 9,
DLLImportLinkage = 10,
DLLExportLinkage = 11,
ExternalWeakLinkage = 12,
GhostLinkage = 13,
CommonLinkage = 14,
LinkerPrivateLinkage = 15,
LinkerPrivateWeakLinkage = 16,
}
#[deriving(Clone)]

View File

@ -85,7 +85,7 @@ struct LoopScope<'a> {
impl<'a, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, O> {
fn pre(&self,
ps: &mut pprust::State<DataFlowContext<'a, O>>,
ps: &mut pprust::State,
node: pprust::AnnNode) -> io::IoResult<()> {
let id = match node {
pprust::NodeExpr(expr) => expr.id,

View File

@ -121,8 +121,6 @@ pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
"extern_weak" => Some(lib::llvm::ExternalWeakLinkage),
"external" => Some(lib::llvm::ExternalLinkage),
"internal" => Some(lib::llvm::InternalLinkage),
"linker_private" => Some(lib::llvm::LinkerPrivateLinkage),
"linker_private_weak" => Some(lib::llvm::LinkerPrivateWeakLinkage),
"linkonce" => Some(lib::llvm::LinkOnceAnyLinkage),
"linkonce_odr" => Some(lib::llvm::LinkOnceODRLinkage),
"private" => Some(lib::llvm::PrivateLinkage),

View File

@ -48,6 +48,8 @@ use util::ppaux::Repr;
use std::rc::Rc;
use std::vec_ng::Vec;
use std::vec_ng;
use collections::HashSet;
use syntax::abi::AbiSet;
use syntax::ast::{RegionTyParamBound, TraitTyParamBound};
use syntax::ast;
@ -478,7 +480,12 @@ fn convert_methods(ccx: &CrateCtxt,
rcvr_visibility: ast::Visibility)
{
let tcx = ccx.tcx;
let mut seen_methods = HashSet::new();
for m in ms.iter() {
if !seen_methods.insert(m.ident.repr(ccx.tcx)) {
tcx.sess.span_err(m.span, "duplicate method in trait impl");
}
let num_rcvr_ty_params = rcvr_ty_generics.type_param_defs().len();
let m_ty_generics = ty_generics_for_fn_or_method(ccx, &m.generics,
num_rcvr_ty_params);

191
src/librustdoc/flock.rs Normal file
View File

@ -0,0 +1,191 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Simple file-locking apis for each OS.
//!
//! This is not meant to be in the standard library, it does nothing with
//! green/native threading. This is just a bare-bones enough solution for
//! librustdoc, it is not production quality at all.
#[allow(non_camel_case_types)];
pub use self::imp::Lock;
#[cfg(unix)]
mod imp {
use std::libc;
#[cfg(target_os = "linux")]
mod os {
use std::libc;
pub struct flock {
l_type: libc::c_short,
l_whence: libc::c_short,
l_start: libc::off_t,
l_len: libc::off_t,
l_pid: libc::pid_t,
// not actually here, but brings in line with freebsd
l_sysid: libc::c_int,
}
pub static F_WRLCK: libc::c_short = 1;
pub static F_UNLCK: libc::c_short = 2;
pub static F_SETLK: libc::c_int = 6;
pub static F_SETLKW: libc::c_int = 7;
}
#[cfg(target_os = "freebsd")]
mod os {
use std::libc;
pub struct flock {
l_start: libc::off_t,
l_len: libc::off_t,
l_pid: libc::pid_t,
l_type: libc::c_short,
l_whence: libc::c_short,
l_sysid: libc::c_int,
}
pub static F_UNLCK: libc::c_short = 2;
pub static F_WRLCK: libc::c_short = 3;
pub static F_SETLK: libc::c_int = 12;
pub static F_SETLKW: libc::c_int = 13;
}
#[cfg(target_os = "macos")]
mod os {
use std::libc;
pub struct flock {
l_start: libc::off_t,
l_len: libc::off_t,
l_pid: libc::pid_t,
l_type: libc::c_short,
l_whence: libc::c_short,
// not actually here, but brings in line with freebsd
l_sysid: libc::c_int,
}
pub static F_UNLCK: libc::c_short = 2;
pub static F_WRLCK: libc::c_short = 3;
pub static F_SETLK: libc::c_int = 8;
pub static F_SETLKW: libc::c_int = 9;
}
pub struct Lock {
priv fd: libc::c_int,
}
impl Lock {
pub fn new(p: &Path) -> Lock {
let fd = p.with_c_str(|s| unsafe {
libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU)
});
assert!(fd > 0);
let flock = os::flock {
l_start: 0,
l_len: 0,
l_pid: 0,
l_whence: libc::SEEK_SET as libc::c_short,
l_type: os::F_WRLCK,
l_sysid: 0,
};
let ret = unsafe {
libc::fcntl(fd, os::F_SETLKW, &flock as *os::flock)
};
if ret == -1 {
unsafe { libc::close(fd); }
fail!("could not lock `{}`", p.display())
}
Lock { fd: fd }
}
}
impl Drop for Lock {
fn drop(&mut self) {
let flock = os::flock {
l_start: 0,
l_len: 0,
l_pid: 0,
l_whence: libc::SEEK_SET as libc::c_short,
l_type: os::F_UNLCK,
l_sysid: 0,
};
unsafe {
libc::fcntl(self.fd, os::F_SETLK, &flock as *os::flock);
libc::close(self.fd);
}
}
}
}
#[cfg(windows)]
mod imp {
use std::libc;
use std::mem;
use std::os::win32::as_utf16_p;
use std::ptr;
static LOCKFILE_EXCLUSIVE_LOCK: libc::DWORD = 0x00000002;
extern "system" {
fn LockFileEx(hFile: libc::HANDLE,
dwFlags: libc::DWORD,
dwReserved: libc::DWORD,
nNumberOfBytesToLockLow: libc::DWORD,
nNumberOfBytesToLockHigh: libc::DWORD,
lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
fn UnlockFileEx(hFile: libc::HANDLE,
dwReserved: libc::DWORD,
nNumberOfBytesToLockLow: libc::DWORD,
nNumberOfBytesToLockHigh: libc::DWORD,
lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
}
pub struct Lock {
priv handle: libc::HANDLE,
}
impl Lock {
pub fn new(p: &Path) -> Lock {
let handle = as_utf16_p(p.as_str().unwrap(), |p| unsafe {
libc::CreateFileW(p, libc::GENERIC_READ, 0, ptr::mut_null(),
libc::CREATE_ALWAYS,
libc::FILE_ATTRIBUTE_NORMAL,
ptr::mut_null())
});
assert!(handle as uint != libc::INVALID_HANDLE_VALUE as uint);
let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
let ret = unsafe {
LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
&mut overlapped)
};
if ret == 0 {
unsafe { libc::CloseHandle(handle); }
fail!("could not lock `{}`", p.display())
}
Lock { handle: handle }
}
}
impl Drop for Lock {
fn drop(&mut self) {
let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
unsafe {
UnlockFileEx(self.handle, 0, 100, 0, &mut overlapped);
libc::CloseHandle(self.handle);
}
}
}
}

View File

@ -37,7 +37,7 @@ pub fn render<T: fmt::Show, S: fmt::Show>(
<link href='http://fonts.googleapis.com/css?family=Oswald:700|Inconsolata:400,700'
rel='stylesheet' type='text/css'>
<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}{krate}/main.css\">
<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}main.css\">
{favicon, select, none{} other{<link rel=\"shortcut icon\" href=\"#\" />}}
</head>
@ -74,13 +74,6 @@ pub fn render<T: fmt::Show, S: fmt::Show>(
<section class=\"footer\"></section>
<script>
var rootPath = \"{root_path}\";
</script>
<script src=\"{root_path}{krate}/jquery.js\"></script>
<script src=\"{root_path}{krate}/search-index.js\"></script>
<script src=\"{root_path}{krate}/main.js\"></script>
<div id=\"help\" class=\"hidden\">
<div class=\"shortcuts\">
<h1>Keyboard shortcuts</h1>
@ -111,6 +104,14 @@ pub fn render<T: fmt::Show, S: fmt::Show>(
</p>
</div>
</div>
<script>
var rootPath = \"{root_path}\";
var currentCrate = \"{krate}\";
</script>
<script src=\"{root_path}jquery.js\"></script>
<script src=\"{root_path}main.js\"></script>
<script async src=\"{root_path}search-index.js\"></script>
</body>
</html>
",

View File

@ -36,7 +36,7 @@
use std::fmt;
use std::local_data;
use std::io;
use std::io::{fs, File, BufferedWriter};
use std::io::{fs, File, BufferedWriter, MemWriter, BufferedReader};
use std::str;
use std::vec;
use std::vec_ng::Vec;
@ -283,48 +283,75 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
};
}
// Add all the static files
let mut dst = cx.dst.join(krate.name.as_slice());
try!(mkdir(&dst));
try!(write(dst.join("jquery.js"),
include_str!("static/jquery-2.1.0.min.js")));
try!(write(dst.join("main.js"), include_str!("static/main.js")));
try!(write(dst.join("main.css"), include_str!("static/main.css")));
try!(write(dst.join("normalize.css"),
include_str!("static/normalize.css")));
// Publish the search index
{
dst.push("search-index.js");
let mut w = BufferedWriter::new(File::create(&dst).unwrap());
let w = &mut w as &mut Writer;
try!(write!(w, "var searchIndex = ["));
let index = {
let mut w = MemWriter::new();
try!(write!(&mut w, "searchIndex['{}'] = [", krate.name));
for (i, item) in cache.search_index.iter().enumerate() {
if i > 0 {
try!(write!(w, ","));
try!(write!(&mut w, ","));
}
try!(write!(w, "\\{ty:\"{}\",name:\"{}\",path:\"{}\",desc:{}",
item.ty, item.name, item.path,
item.desc.to_json().to_str()));
try!(write!(&mut w, "\\{ty:\"{}\",name:\"{}\",path:\"{}\",desc:{}",
item.ty, item.name, item.path,
item.desc.to_json().to_str()));
match item.parent {
Some(id) => {
try!(write!(w, ",parent:'{}'", id));
try!(write!(&mut w, ",parent:'{}'", id));
}
None => {}
}
try!(write!(w, "\\}"));
try!(write!(&mut w, "\\}"));
}
try!(write!(w, "];"));
try!(write!(w, "var allPaths = \\{"));
try!(write!(&mut w, "];"));
try!(write!(&mut w, "allPaths['{}'] = \\{", krate.name));
for (i, (&id, &(ref fqp, short))) in cache.paths.iter().enumerate() {
if i > 0 {
try!(write!(w, ","));
try!(write!(&mut w, ","));
}
try!(write!(w, "'{}':\\{type:'{}',name:'{}'\\}",
id, short, *fqp.last().unwrap()));
try!(write!(&mut w, "'{}':\\{type:'{}',name:'{}'\\}",
id, short, *fqp.last().unwrap()));
}
try!(write!(w, "\\};"));
try!(w.flush());
try!(write!(&mut w, "\\};"));
str::from_utf8_owned(w.unwrap()).unwrap()
};
// Write out the shared files. Note that these are shared among all rustdoc
// docs placed in the output directory, so this needs to be a synchronized
// operation with respect to all other rustdocs running around.
{
try!(mkdir(&cx.dst));
let _lock = ::flock::Lock::new(&cx.dst.join(".lock"));
// Add all the static files. These may already exist, but we just
// overwrite them anyway to make sure that they're fresh and up-to-date.
try!(write(cx.dst.join("jquery.js"),
include_str!("static/jquery-2.1.0.min.js")));
try!(write(cx.dst.join("main.js"), include_str!("static/main.js")));
try!(write(cx.dst.join("main.css"), include_str!("static/main.css")));
try!(write(cx.dst.join("normalize.css"),
include_str!("static/normalize.css")));
// Update the search index
let dst = cx.dst.join("search-index.js");
let mut all_indexes = Vec::new();
all_indexes.push(index);
if dst.exists() {
for line in BufferedReader::new(File::open(&dst)).lines() {
let line = try!(line);
if !line.starts_with("searchIndex") { continue }
if line.starts_with(format!("searchIndex['{}']", krate.name)) {
continue
}
all_indexes.push(line);
}
}
let mut w = try!(File::create(&dst));
try!(writeln!(&mut w, r"var searchIndex = \{\}; var allPaths = \{\};"));
for index in all_indexes.iter() {
try!(writeln!(&mut w, "{}", *index));
}
try!(writeln!(&mut w, "initSearch(searchIndex);"));
}
// Render all source files (this may turn into a giant no-op)
@ -463,6 +490,13 @@ impl<'a> SourceCollector<'a> {
};
let contents = str::from_utf8_owned(contents).unwrap();
// Remove the utf-8 BOM if any
let contents = if contents.starts_with("\ufeff") {
contents.as_slice().slice_from(3)
} else {
contents.as_slice()
};
// Create the intermediate directories
let mut cur = self.dst.clone();
let mut root_path = ~"../../";
@ -482,7 +516,7 @@ impl<'a> SourceCollector<'a> {
root_path: root_path,
};
try!(layout::render(&mut w as &mut Writer, &self.cx.layout,
&page, &(""), &Source(contents.as_slice())));
&page, &(""), &Source(contents)));
try!(w.flush());
return Ok(());
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
/*jslint browser: true, es5: true */
/*globals $: true, searchIndex: true, rootPath: true, allPaths: true */
/*globals $: true, rootPath: true, allPaths: true */
(function() {
"use strict";
@ -23,7 +23,8 @@
map(function(s) {
var pair = s.split("=");
params[decodeURIComponent(pair[0])] =
typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]);
typeof pair[1] === "undefined" ?
null : decodeURIComponent(pair[1]);
});
return params;
}
@ -111,8 +112,9 @@
document.location.href = url;
});
function initSearch(searchIndex) {
var currentResults, index, params = getQueryStringParams();
function initSearch(rawSearchIndex) {
var currentResults, index, searchIndex;
var params = getQueryStringParams();
// Populate search bar with query string search term when provided,
// but only if the input bar is empty. This avoid the obnoxious issue
@ -126,7 +128,8 @@
* Executes the query and builds an index of results
* @param {[Object]} query [The user query]
* @param {[type]} max [The maximum results returned]
* @param {[type]} searchWords [The list of search words to query against]
* @param {[type]} searchWords [The list of search words to query
* against]
* @return {[type]} [A search index of results]
*/
function execQuery(query, max, searchWords) {
@ -148,7 +151,9 @@
// quoted values mean literal search
bb = searchWords.length;
if ((val.charAt(0) === "\"" || val.charAt(0) === "'") && val.charAt(val.length - 1) === val.charAt(0)) {
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) {
@ -166,7 +171,10 @@
val = val.replace(/\_/g, "");
for (var i = 0; i < split.length; i++) {
for (aa = 0; aa < bb; aa += 1) {
if (searchWords[aa].indexOf(split[i]) > -1 || searchWords[aa].indexOf(val) > -1 || searchWords[aa].replace(/_/g, "").indexOf(val) > -1) {
if (searchWords[aa].indexOf(split[i]) > -1 ||
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)]);
@ -185,6 +193,7 @@
results[aa].push(searchIndex[results[aa][0]].path);
results[aa].push(searchIndex[results[aa][0]].name);
results[aa].push(searchIndex[results[aa][0]].parent);
results[aa].push(searchIndex[results[aa][0]].crate);
}
// if there are no results then return to default and fail
if (results.length === 0) {
@ -193,7 +202,8 @@
// sort by exact match
results.sort(function search_complete_sort0(aaa, bbb) {
if (searchWords[aaa[0]] === valLower && searchWords[bbb[0]] !== valLower) {
if (searchWords[aaa[0]] === valLower &&
searchWords[bbb[0]] !== valLower) {
return 1;
}
});
@ -207,7 +217,8 @@
// 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]]) {
if (searchWords[aaa[0]].length === searchWords[bbb[0]].length &&
searchWords[aaa[0]] > searchWords[bbb[0]]) {
return 1;
}
});
@ -223,21 +234,26 @@
// 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]) {
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]) {
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]) {
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;
}
}
@ -245,7 +261,7 @@
var result = results[i],
name = result[4].toLowerCase(),
path = result[3].toLowerCase(),
parent = allPaths[result[5]];
parent = allPaths[result[6]][result[5]];
var valid = validateResult(name, path, split, parent);
if (!valid) {
@ -256,11 +272,14 @@
}
/**
* Validate performs the following boolean logic. For example: "File::open" will give
* IF A PARENT EXISTS => ("file" && "open") exists in (name || path || parent)
* OR => ("file" && "open") exists in (name || path )
* Validate performs the following boolean logic. For example:
* "File::open" will give IF A PARENT EXISTS => ("file" && "open")
* exists in (name || path || parent) OR => ("file" && "open") exists in
* (name || path )
*
* This could be written functionally, but I wanted to minimise
* functions on stack.
*
* This could be written functionally, but I wanted to minimise functions on stack.
* @param {[string]} name [The name of the result]
* @param {[string]} path [The path of the result]
* @param {[string]} keys [The keys to be used (["file", "open"])]
@ -273,8 +292,13 @@
//if there is a parent, then validate against parent
if (parent !== undefined) {
for (var i = 0; i < keys.length; i++) {
// if previous keys are valid and current key is in the path, name or parent
if ((validate) && (name.toLowerCase().indexOf(keys[i]) > -1 || path.toLowerCase().indexOf(keys[i]) > -1 || parent.name.toLowerCase().indexOf(keys[i]) > -1)) {
// if previous keys are valid and current key is in the
// path, name or parent
if ((validate) &&
(name.toLowerCase().indexOf(keys[i]) > -1 ||
path.toLowerCase().indexOf(keys[i]) > -1 ||
parent.name.toLowerCase().indexOf(keys[i]) > -1))
{
validate = true;
} else {
validate = false;
@ -282,8 +306,12 @@
}
} else {
for (var i = 0; i < keys.length; i++) {
// if previous keys are valid and current key is in the path, name
if ((validate) && (name.toLowerCase().indexOf(keys[i]) > -1 || path.toLowerCase().indexOf(keys[i]) > -1)) {
// if previous keys are valid and current key is in the
// path, name
if ((validate) &&
(name.toLowerCase().indexOf(keys[i]) > -1 ||
path.toLowerCase().indexOf(keys[i]) > -1))
{
validate = true;
} else {
validate = false;
@ -298,7 +326,10 @@
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');
type = matches[1].replace(/^td$/, 'typedef')
.replace(/^str$/, 'struct')
.replace(/^tdef$/, 'typedef')
.replace(/^typed$/, 'typedef');
query = query.substring(matches[0].length);
}
@ -314,7 +345,6 @@
$results.on('click', function() {
var dst = $(this).find('a')[0];
console.log(window.location.pathname, dst.pathname);
if (window.location.pathname == dst.pathname) {
$('#search').addClass('hidden');
$('#main').removeClass('hidden');
@ -362,7 +392,8 @@
var output, shown, query = getQuery();
currentResults = query.id;
output = '<h1>Results for ' + query.query + (query.type ? ' (type: ' + query.type + ')' : '') + '</h1>';
output = '<h1>Results for ' + query.query +
(query.type ? ' (type: ' + query.type + ')' : '') + '</h1>';
output += '<table class="search-results">';
if (results.length > 0) {
@ -394,7 +425,7 @@
'/index.html" class="' + type +
'">' + name + '</a>';
} else if (item.parent !== undefined) {
var myparent = allPaths[item.parent];
var myparent = allPaths[item.crate][item.parent];
var anchor = '#' + type + '.' + name;
output += item.path + '::' + myparent.name +
'::<a href="' + rootPath +
@ -449,13 +480,15 @@
return;
}
// Because searching is incremental by character, only the most recent search query
// is added to the browser history.
// Because searching is incremental by character, only the most
// recent search query is added to the browser history.
if (browserSupportsHistoryApi()) {
if (!history.state && !params.search) {
history.pushState(query, "", "?search=" + encodeURIComponent(query.query));
history.pushState(query, "", "?search=" +
encodeURIComponent(query.query));
} else {
history.replaceState(query, "", "?search=" + encodeURIComponent(query.query));
history.replaceState(query, "", "?search=" +
encodeURIComponent(query.query));
}
}
@ -472,91 +505,33 @@
}
}
// 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 = [];
function buildIndex(rawSearchIndex) {
searchIndex = [];
var searchWords = [];
for (var crate in rawSearchIndex) {
if (!rawSearchIndex.hasOwnProperty(crate)) { continue }
var len = rawSearchIndex[crate].length;
var i = 0;
// 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("");
// 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) {
rawSearchIndex[crate][i].crate = crate;
searchIndex.push(rawSearchIndex[crate][i]);
if (typeof rawSearchIndex[crate][i].name === "string") {
var word = rawSearchIndex[crate][i].name.toLowerCase();
searchWords.push(word);
} else {
searchWords.push("");
}
}
}
return searchWords;
}
@ -567,17 +542,21 @@
clearTimeout(keyUpTimeout);
keyUpTimeout = setTimeout(search, 100);
});
// Push and pop states are used to add search results to the browser history.
// Push and pop states are used to add search results to the browser
// history.
if (browserSupportsHistoryApi()) {
$(window).on('popstate', function(e) {
var params = getQueryStringParams();
// When browsing back from search results the main page visibility must be reset.
// When browsing back from search results the main page
// visibility must be reset.
if (!params.search) {
$('#main.content').removeClass('hidden');
$('#search.content').addClass('hidden');
}
// When browsing forward to search results the previous search will be repeated,
// so the currentResults are cleared to ensure the search is successful.
// When browsing forward to search results the previous
// search will be repeated, so the currentResults are
// cleared to ensure the search is successful.
currentResults = null;
// Synchronize search bar with query string state and
// perform the search, but don't empty the bar if there's
@ -585,19 +564,46 @@
if (params.search !== undefined) {
$('.search-input').val(params.search);
}
// Some browsers fire 'onpopstate' for every page load (Chrome), while others fire the
// event only when actually popping a state (Firefox), which is why search() is called
// both here and at the end of the startSearch() function.
// Some browsers fire 'onpopstate' for every page load
// (Chrome), while others fire the event only when actually
// popping a state (Firefox), which is why search() is
// called both here and at the end of the startSearch()
// function.
search();
});
}
search();
}
index = buildIndex(searchIndex);
index = buildIndex(rawSearchIndex);
startSearch();
// Draw a convenient sidebar of known crates if we have a listing
if (rootPath == '../') {
console.log('here');
var sidebar = $('.sidebar');
var div = $('<div>').attr('class', 'block crate');
div.append($('<h2>').text('Crates'));
var crates = [];
for (var crate in rawSearchIndex) {
if (!rawSearchIndex.hasOwnProperty(crate)) { continue }
crates.push(crate);
}
crates.sort();
for (var i = 0; i < crates.length; i++) {
var klass = 'crate';
if (crates[i] == window.currentCrate) {
klass += ' current';
}
div.append($('<a>', {'href': '../' + crates[i] + '/index.html',
'class': klass}).text(crates[i]));
div.append($('<br>'));
}
sidebar.append(div);
}
}
initSearch(searchIndex);
window.initSearch = initSearch;
}());

View File

@ -52,6 +52,7 @@ pub mod passes;
pub mod plugins;
pub mod visit_ast;
pub mod test;
mod flock;
pub static SCHEMA_VERSION: &'static str = "0.8.1";

View File

@ -464,8 +464,20 @@ impl<'a> ::Encoder for Encoder<'a> {
}
fn emit_map_elt_key(&mut self, idx: uint, f: |&mut Encoder<'a>|) {
use std::str::from_utf8;
if idx != 0 { try!(write!(self.wr, ",")) }
f(self)
// ref #12967, make sure to wrap a key in double quotes,
// in the event that its of a type that omits them (eg numbers)
let mut buf = MemWriter::new();
let mut check_encoder = Encoder::new(&mut buf);
f(&mut check_encoder);
let buf = buf.unwrap();
let out = from_utf8(buf).unwrap();
let needs_wrapping = out.char_at(0) != '"' &&
out.char_at_reverse(out.len()) != '"';
if needs_wrapping { try!(write!(self.wr, "\"")); }
f(self);
if needs_wrapping { try!(write!(self.wr, "\"")); }
}
fn emit_map_elt_val(&mut self, _idx: uint, f: |&mut Encoder<'a>|) {
@ -659,13 +671,25 @@ impl<'a> ::Encoder for PrettyEncoder<'a> {
}
fn emit_map_elt_key(&mut self, idx: uint, f: |&mut PrettyEncoder<'a>|) {
use std::str::from_utf8;
if idx == 0 {
try!(write!(self.wr, "\n"));
} else {
try!(write!(self.wr, ",\n"));
}
try!(write!(self.wr, "{}", spaces(self.indent)));
// ref #12967, make sure to wrap a key in double quotes,
// in the event that its of a type that omits them (eg numbers)
let mut buf = MemWriter::new();
let mut check_encoder = PrettyEncoder::new(&mut buf);
f(&mut check_encoder);
let buf = buf.unwrap();
let out = from_utf8(buf).unwrap();
let needs_wrapping = out.char_at(0) != '"' &&
out.char_at_reverse(out.len()) != '"';
if needs_wrapping { try!(write!(self.wr, "\"")); }
f(self);
if needs_wrapping { try!(write!(self.wr, "\"")); }
}
fn emit_map_elt_val(&mut self, _idx: uint, f: |&mut PrettyEncoder<'a>|) {
@ -1306,13 +1330,19 @@ impl ::Decoder for Decoder {
}
fn read_f64(&mut self) -> f64 {
use std::from_str::FromStr;
debug!("read_f64");
match self.stack.pop().unwrap() {
Number(f) => f,
String(s) => {
// re: #12967.. a type w/ numeric keys (ie HashMap<uint, V> etc)
// is going to have a string here, as per JSON spec..
FromStr::from_str(s).unwrap()
},
value => self.expected("number", &value)
}
}
fn read_f32(&mut self) -> f32 { self.read_f64() as f32 }
fn read_f32(&mut self) -> f32 { self.read_f64() as f32 }
fn read_char(&mut self) -> char {
@ -2519,4 +2549,57 @@ mod tests {
let expected_null = ();
assert!(json_null.is_some() && json_null.unwrap() == expected_null);
}
#[test]
fn test_encode_hashmap_with_numeric_key() {
use std::str::from_utf8;
use std::io::Writer;
use std::io::MemWriter;
use collections::HashMap;
let mut hm: HashMap<uint, bool> = HashMap::new();
hm.insert(1, true);
let mut mem_buf = MemWriter::new();
{
let mut encoder = Encoder::new(&mut mem_buf as &mut io::Writer);
hm.encode(&mut encoder)
}
let bytes = mem_buf.unwrap();
let json_str = from_utf8(bytes).unwrap();
match from_str(json_str) {
Err(_) => fail!("Unable to parse json_str: {:?}", json_str),
_ => {} // it parsed and we are good to go
}
}
#[test]
fn test_prettyencode_hashmap_with_numeric_key() {
use std::str::from_utf8;
use std::io::Writer;
use std::io::MemWriter;
use collections::HashMap;
let mut hm: HashMap<uint, bool> = HashMap::new();
hm.insert(1, true);
let mut mem_buf = MemWriter::new();
{
let mut encoder = PrettyEncoder::new(&mut mem_buf as &mut io::Writer);
hm.encode(&mut encoder)
}
let bytes = mem_buf.unwrap();
let json_str = from_utf8(bytes).unwrap();
match from_str(json_str) {
Err(_) => fail!("Unable to parse json_str: {:?}", json_str),
_ => {} // it parsed and we are good to go
}
}
#[test]
fn test_hashmap_with_numeric_key_can_handle_double_quote_delimited_key() {
use collections::HashMap;
use Decodable;
let json_str = "{\"1\":true}";
let json_obj = match from_str(json_str) {
Err(_) => fail!("Unable to parse json_str: {:?}", json_str),
Ok(o) => o
};
let mut decoder = Decoder::new(json_obj);
let hm: HashMap<uint, bool> = Decodable::decode(&mut decoder);
}
}

View File

@ -20,6 +20,7 @@ use cast;
use fmt;
use iter::Iterator;
use vec::{ImmutableVector, MutableVector, Vector};
use vec_ng::Vec;
use option::{Option, Some, None};
/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
@ -305,6 +306,14 @@ impl IntoStr for ~[Ascii] {
}
}
impl IntoStr for Vec<Ascii> {
#[inline]
fn into_str(self) -> ~str {
let v: ~[Ascii] = self.move_iter().collect();
unsafe { cast::transmute(v) }
}
}
/// Trait to convert to an owned byte array by consuming self
pub trait IntoBytes {
/// Converts to an owned byte array by consuming self
@ -473,6 +482,7 @@ mod tests {
use super::*;
use str::from_char;
use char::from_u32;
use vec_ng::Vec;
macro_rules! v2ascii (
( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
@ -480,6 +490,10 @@ mod tests {
(~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
)
macro_rules! vec2ascii (
($($e:expr),*) => (Vec::from_slice([$(Ascii{chr:$e}),*]));
)
#[test]
fn test_ascii() {
assert_eq!(65u8.to_ascii().to_byte(), 65u8);
@ -535,6 +549,17 @@ mod tests {
}
#[test]
fn test_ascii_vec_ng() {
assert_eq!(Vec::from_slice("abCDef&?#".to_ascii().to_lower()).into_str(), ~"abcdef&?#");
assert_eq!(Vec::from_slice("abCDef&?#".to_ascii().to_upper()).into_str(), ~"ABCDEF&?#");
assert_eq!(Vec::from_slice("".to_ascii().to_lower()).into_str(), ~"");
assert_eq!(Vec::from_slice("YMCA".to_ascii().to_lower()).into_str(), ~"ymca");
assert_eq!(Vec::from_slice("abcDEFxyz:.;".to_ascii().to_upper()).into_str(),
~"ABCDEFXYZ:.;");
}
#[test]
fn test_owned_ascii_vec() {
assert_eq!((~"( ;").into_ascii(), v2ascii!(~[40, 32, 59]));
@ -550,6 +575,7 @@ mod tests {
#[test]
fn test_ascii_into_str() {
assert_eq!(v2ascii!(~[40, 32, 59]).into_str(), ~"( ;");
assert_eq!(vec2ascii!(40, 32, 59).into_str(), ~"( ;");
}
#[test]

View File

@ -45,8 +45,9 @@ impl<T: Clone> Clone for ~T {
fn clone(&self) -> ~T { ~(**self).clone() }
/// Perform copy-assignment from `source` by reusing the existing allocation.
#[inline]
fn clone_from(&mut self, source: &~T) {
**self = (**source).clone()
(**self).clone_from(&(**source));
}
}

View File

@ -3643,7 +3643,7 @@ pub mod funcs {
pub fn open(path: *c_char, oflag: c_int, mode: c_int)
-> c_int;
pub fn creat(path: *c_char, mode: mode_t) -> c_int;
pub fn fcntl(fd: c_int, cmd: c_int) -> c_int;
pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int;
}
}

View File

@ -8,9 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// So we don't have to document the actual methods on the traits.
#[allow(missing_doc)];
/*!
*
* Traits representing built-in operators, useful for overloading
@ -83,6 +80,7 @@
*/
#[lang="drop"]
pub trait Drop {
/// The `drop` method, called when the value goes out of scope.
fn drop(&mut self);
}
@ -112,6 +110,7 @@ pub trait Drop {
*/
#[lang="add"]
pub trait Add<RHS,Result> {
/// The method for the `+` operator
fn add(&self, rhs: &RHS) -> Result;
}
@ -141,6 +140,7 @@ pub trait Add<RHS,Result> {
*/
#[lang="sub"]
pub trait Sub<RHS,Result> {
/// The method for the `-` operator
fn sub(&self, rhs: &RHS) -> Result;
}
@ -170,6 +170,7 @@ pub trait Sub<RHS,Result> {
*/
#[lang="mul"]
pub trait Mul<RHS,Result> {
/// The method for the `*` operator
fn mul(&self, rhs: &RHS) -> Result;
}
@ -199,6 +200,7 @@ pub trait Mul<RHS,Result> {
*/
#[lang="div"]
pub trait Div<RHS,Result> {
/// The method for the `/` operator
fn div(&self, rhs: &RHS) -> Result;
}
@ -228,6 +230,7 @@ pub trait Div<RHS,Result> {
*/
#[lang="rem"]
pub trait Rem<RHS,Result> {
/// The method for the `%` operator
fn rem(&self, rhs: &RHS) -> Result;
}
@ -257,6 +260,7 @@ pub trait Rem<RHS,Result> {
*/
#[lang="neg"]
pub trait Neg<Result> {
/// The method for the unary `-` operator
fn neg(&self) -> Result;
}
@ -286,6 +290,7 @@ pub trait Neg<Result> {
*/
#[lang="not"]
pub trait Not<Result> {
/// The method for the unary `!` operator
fn not(&self) -> Result;
}
@ -315,6 +320,7 @@ pub trait Not<Result> {
*/
#[lang="bitand"]
pub trait BitAnd<RHS,Result> {
/// The method for the `&` operator
fn bitand(&self, rhs: &RHS) -> Result;
}
@ -344,6 +350,7 @@ pub trait BitAnd<RHS,Result> {
*/
#[lang="bitor"]
pub trait BitOr<RHS,Result> {
/// The method for the `|` operator
fn bitor(&self, rhs: &RHS) -> Result;
}
@ -373,6 +380,7 @@ pub trait BitOr<RHS,Result> {
*/
#[lang="bitxor"]
pub trait BitXor<RHS,Result> {
/// The method for the `^` operator
fn bitxor(&self, rhs: &RHS) -> Result;
}
@ -402,6 +410,7 @@ pub trait BitXor<RHS,Result> {
*/
#[lang="shl"]
pub trait Shl<RHS,Result> {
/// The method for the `<<` operator
fn shl(&self, rhs: &RHS) -> Result;
}
@ -431,6 +440,7 @@ pub trait Shl<RHS,Result> {
*/
#[lang="shr"]
pub trait Shr<RHS,Result> {
/// The method for the `>>` operator
fn shr(&self, rhs: &RHS) -> Result;
}
@ -461,28 +471,96 @@ pub trait Shr<RHS,Result> {
*/
#[lang="index"]
pub trait Index<Index,Result> {
/// The method for the indexing (`Foo[Bar]`) operation
fn index(&self, index: &Index) -> Result;
}
/// Dummy dox
#[cfg(stage0)]
pub trait Deref<Result> {
/// dummy dox
fn deref<'a>(&'a self) -> &'a Result;
}
/**
*
* The `Deref` trait is used to specify the functionality of dereferencing
* operations like `*v`.
*
* # Example
*
* A struct with a single field which is accessible via dereferencing the
* struct.
*
* ```
* struct DerefExample<T> {
* value: T
* }
*
* impl<T> Deref<T> for DerefExample<T> {
* fn deref<'a>(&'a self) -> &'a T {
* &self.value
* }
* }
*
* fn main() {
* let x = DerefExample { value: 'a' };
* assert_eq!('a', *x);
* }
* ```
*/
#[cfg(not(stage0))]
#[lang="deref"]
pub trait Deref<Result> {
/// The method called to dereference a value
fn deref<'a>(&'a self) -> &'a Result;
}
/// dummy dox
#[cfg(stage0)]
pub trait DerefMut<Result>: Deref<Result> {
/// dummy dox
fn deref_mut<'a>(&'a mut self) -> &'a mut Result;
}
/**
*
* The `DerefMut` trait is used to specify the functionality of dereferencing
* mutably like `*v = 1;`
*
* # Example
*
* A struct with a single field which is modifiable via dereferencing the
* struct.
*
* ```
* struct DerefMutExample<T> {
* value: T
* }
*
* impl<T> Deref<T> for DerefMutExample<T> {
* fn deref<'a>(&'a self) -> &'a T {
* &self.value
* }
* }
*
* impl<T> DerefMut<T> for DerefMutExample<T> {
* fn deref_mut<'a>(&'a mut self) -> &'a mut T {
* &mut self.value
* }
* }
*
* fn main() {
* let mut x = DerefMutExample { value: 'a' };
* *x = 'b';
* assert_eq!('b', *x);
* }
* ```
*/
#[cfg(not(stage0))]
#[lang="deref_mut"]
pub trait DerefMut<Result>: Deref<Result> {
/// The method called to mutably dereference a value
fn deref_mut<'a>(&'a mut self) -> &'a mut Result;
}

View File

@ -149,7 +149,7 @@ impl<T> Option<T> {
}
}
/// Returns the contained value or a default
/// Returns the contained value or a default.
#[inline]
pub fn unwrap_or(self, def: T) -> T {
match self {
@ -158,7 +158,7 @@ impl<T> Option<T> {
}
}
/// Returns the contained value or computes it from a closure
/// Returns the contained value or computes it from a closure.
#[inline]
pub fn unwrap_or_else(self, f: || -> T) -> T {
match self {
@ -183,7 +183,7 @@ impl<T> Option<T> {
match self { None => def, Some(t) => f(t) }
}
/// Apply a function to the contained value or do nothing.
/// Applies a function to the contained value or does nothing.
/// Returns true if the contained value was mutated.
pub fn mutate(&mut self, f: |T| -> T) -> bool {
if self.is_some() {
@ -192,7 +192,7 @@ impl<T> Option<T> {
} else { false }
}
/// Apply a function to the contained value or set it to a default.
/// Applies a function to the contained value or sets it to a default.
/// Returns true if the contained value was mutated, or false if set to the default.
pub fn mutate_or_set(&mut self, def: T, f: |T| -> T) -> bool {
if self.is_some() {
@ -208,19 +208,19 @@ impl<T> Option<T> {
// Iterator constructors
/////////////////////////////////////////////////////////////////////////
/// Return an iterator over the possibly contained value
/// Returns an iterator over the possibly contained value.
#[inline]
pub fn iter<'r>(&'r self) -> Item<&'r T> {
Item{opt: self.as_ref()}
}
/// Return a mutable iterator over the possibly contained value
/// Returns a mutable iterator over the possibly contained value.
#[inline]
pub fn mut_iter<'r>(&'r mut self) -> Item<&'r mut T> {
Item{opt: self.as_mut()}
}
/// Return a consuming iterator over the possibly contained value
/// Returns a consuming iterator over the possibly contained value.
#[inline]
pub fn move_iter(self) -> Item<T> {
Item{opt: self}
@ -264,7 +264,7 @@ impl<T> Option<T> {
pub fn or_else(self, f: || -> Option<T>) -> Option<T> {
match self {
Some(_) => self,
None => f(),
None => f()
}
}
@ -272,7 +272,7 @@ impl<T> Option<T> {
// Misc
/////////////////////////////////////////////////////////////////////////
/// Take the value out of the option, leaving a `None` in its place.
/// Takes the value out of the option, leaving a `None` in its place.
#[inline]
pub fn take(&mut self) -> Option<T> {
mem::replace(self, None)
@ -282,7 +282,7 @@ impl<T> Option<T> {
#[inline(always)]
pub fn filtered(self, f: |t: &T| -> bool) -> Option<T> {
match self {
Some(x) => if f(&x) {Some(x)} else {None},
Some(x) => if f(&x) { Some(x) } else { None },
None => None
}
}

View File

@ -2664,9 +2664,6 @@ impl<'a> StrSlice<'a> for &'a str {
return multibyte_char_range_at(*self, i);
}
#[inline]
fn char_at(&self, i: uint) -> char { self.char_range_at(i).ch }
#[inline]
fn char_range_at_reverse(&self, start: uint) -> CharRange {
let mut prev = start;

View File

@ -1,4 +1,4 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -26,7 +26,7 @@ use clone::Clone;
use kinds::Send;
use ops::Drop;
use ptr::RawPtr;
use sync::atomics::{AtomicUint, SeqCst, Relaxed, Acquire};
use sync::atomics::{fence, AtomicUint, Relaxed, Acquire, Release};
use vec;
/// An atomically reference counted pointer.
@ -109,8 +109,16 @@ impl<T: Send> UnsafeArc<T> {
impl<T: Send> Clone for UnsafeArc<T> {
fn clone(&self) -> UnsafeArc<T> {
unsafe {
// This barrier might be unnecessary, but I'm not sure...
let old_count = (*self.data).count.fetch_add(1, Acquire);
// Using a relaxed ordering is alright here, as knowledge of the original reference
// prevents other threads from erroneously deleting the object.
//
// As explained in the [Boost documentation][1],
// Increasing the reference counter can always be done with memory_order_relaxed: New
// references to an object can only be formed from an existing reference, and passing
// an existing reference from one thread to another must already provide any required
// synchronization.
// [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
let old_count = (*self.data).count.fetch_add(1, Relaxed);
// FIXME(#12049): this needs some sort of debug assertion
if cfg!(test) { assert!(old_count >= 1); }
return UnsafeArc { data: self.data };
@ -127,12 +135,26 @@ impl<T> Drop for UnsafeArc<T>{
if self.data.is_null() {
return
}
// Must be acquire+release, not just release, to make sure this
// doesn't get reordered to after the unwrapper pointer load.
let old_count = (*self.data).count.fetch_sub(1, SeqCst);
// Because `fetch_sub` is already atomic, we do not need to synchronize with other
// threads unless we are going to delete the object.
let old_count = (*self.data).count.fetch_sub(1, Release);
// FIXME(#12049): this needs some sort of debug assertion
if cfg!(test) { assert!(old_count >= 1); }
if old_count == 1 {
// This fence is needed to prevent reordering of use of the data and deletion of
// the data. Because it is marked `Release`, the decreasing of the reference count
// sychronizes with this `Acquire` fence. This means that use of the data happens
// before decreasing the refernce count, which happens before this fence, which
// happens before the deletion of the data.
//
// As explained in the [Boost documentation][1],
// It is important to enforce any possible access to the object in one thread
// (through an existing reference) to *happen before* deleting the object in a
// different thread. This is achieved by a "release" operation after dropping a
// reference (any access to the object through this reference must obviously
// happened before), and an "acquire" operation before deleting the object.
// [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
fence(Acquire);
let _: ~ArcData<T> = cast::transmute(self.data);
}
}

View File

@ -427,7 +427,7 @@ impl<T> Vec<T> {
}
}
fn remove(&mut self, index: uint) -> Option<T> {
pub fn remove(&mut self, index: uint) -> Option<T> {
let len = self.len();
if index < len {
unsafe { // infallible

View File

@ -271,13 +271,22 @@ impl CodeMap {
}
}
pub fn new_filemap(&self, filename: FileName, mut src: ~str) -> Rc<FileMap> {
pub fn new_filemap(&self, filename: FileName, src: ~str) -> Rc<FileMap> {
let mut files = self.files.borrow_mut();
let start_pos = match files.get().last() {
None => 0,
Some(last) => last.deref().start_pos.to_uint() + last.deref().src.len(),
};
// Remove utf-8 BOM if any.
// FIXME #12884: no efficient/safe way to remove from the start of a string
// and reuse the allocation.
let mut src = if src.starts_with("\ufeff") {
src.as_slice().slice_from(3).into_owned()
} else {
src
};
// Append '\n' in case it's not already there.
// This is a workaround to prevent CodeMap.lookup_filemap_idx from accidentally
// overflowing into the next filemap in case the last byte of span is also the last

View File

@ -880,8 +880,8 @@ mod test {
use super::*;
// this version doesn't care about getting comments or docstrings in.
fn fake_print_crate<A: pprust::PpAnn>(s: &mut pprust::State<A>,
krate: &ast::Crate) -> io::IoResult<()> {
fn fake_print_crate(s: &mut pprust::State,
krate: &ast::Crate) -> io::IoResult<()> {
s.print_mod(&krate.module, krate.attrs.as_slice())
}

View File

@ -43,8 +43,8 @@ pub enum AnnNode<'a> {
}
pub trait PpAnn {
fn pre(&self, _state: &mut State<Self>, _node: AnnNode) -> IoResult<()> { Ok(()) }
fn post(&self, _state: &mut State<Self>, _node: AnnNode) -> IoResult<()> { Ok(()) }
fn pre(&self, _state: &mut State, _node: AnnNode) -> IoResult<()> { Ok(()) }
fn post(&self, _state: &mut State, _node: AnnNode) -> IoResult<()> { Ok(()) }
}
pub struct NoAnn;
@ -56,7 +56,7 @@ pub struct CurrentCommentAndLiteral {
cur_lit: uint,
}
pub struct State<'a, A> {
pub struct State<'a> {
s: pp::Printer,
cm: Option<&'a CodeMap>,
intr: @token::IdentInterner,
@ -64,15 +64,16 @@ pub struct State<'a, A> {
literals: Option<Vec<comments::Literal> >,
cur_cmnt_and_lit: CurrentCommentAndLiteral,
boxes: RefCell<Vec<pp::Breaks> >,
ann: &'a A
ann: &'a PpAnn
}
pub fn rust_printer(writer: ~io::Writer) -> State<'static, NoAnn> {
pub fn rust_printer(writer: ~io::Writer) -> State<'static> {
static NO_ANN: NoAnn = NoAnn;
rust_printer_annotated(writer, &NO_ANN)
}
pub fn rust_printer_annotated<'a, A: PpAnn>(writer: ~io::Writer, ann: &'a A) -> State<'a, A> {
pub fn rust_printer_annotated<'a>(writer: ~io::Writer,
ann: &'a PpAnn) -> State<'a> {
State {
s: pp::mk_printer(writer, default_columns),
cm: None,
@ -95,14 +96,14 @@ pub static default_columns: uint = 78u;
// Requires you to pass an input filename and reader so that
// it can scan the input text for comments and literals to
// copy forward.
pub fn print_crate<'a, A: PpAnn>(cm: &'a CodeMap,
span_diagnostic: &diagnostic::SpanHandler,
krate: &ast::Crate,
filename: ~str,
input: &mut io::Reader,
out: ~io::Writer,
ann: &'a A,
is_expanded: bool) -> IoResult<()> {
pub fn print_crate<'a>(cm: &'a CodeMap,
span_diagnostic: &diagnostic::SpanHandler,
krate: &ast::Crate,
filename: ~str,
input: &mut io::Reader,
out: ~io::Writer,
ann: &'a PpAnn,
is_expanded: bool) -> IoResult<()> {
let (cmnts, lits) = comments::gather_comments_and_literals(
span_diagnostic,
filename,
@ -133,7 +134,7 @@ pub fn print_crate<'a, A: PpAnn>(cm: &'a CodeMap,
eof(&mut s.s)
}
pub fn to_str(f: |&mut State<NoAnn>| -> IoResult<()>) -> ~str {
pub fn to_str(f: |&mut State| -> IoResult<()>) -> ~str {
let mut s = rust_printer(~MemWriter::new());
f(&mut s).unwrap();
eof(&mut s.s).unwrap();
@ -237,7 +238,7 @@ pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> ~str {
}
}
impl<'a, A: PpAnn> State<'a, A> {
impl<'a> State<'a> {
pub fn ibox(&mut self, u: uint) -> IoResult<()> {
self.boxes.borrow_mut().get().push(pp::Inconsistent);
pp::ibox(&mut self.s, u)
@ -365,7 +366,7 @@ impl<'a, A: PpAnn> State<'a, A> {
}
pub fn commasep<T>(&mut self, b: Breaks, elts: &[T],
op: |&mut State<A>, &T| -> IoResult<()>)
op: |&mut State, &T| -> IoResult<()>)
-> IoResult<()> {
try!(self.rbox(0u, b));
let mut first = true;
@ -381,7 +382,7 @@ impl<'a, A: PpAnn> State<'a, A> {
&mut self,
b: Breaks,
elts: &[T],
op: |&mut State<A>, &T| -> IoResult<()>,
op: |&mut State, &T| -> IoResult<()>,
get_span: |&T| -> codemap::Span) -> IoResult<()> {
try!(self.rbox(0u, b));
let len = elts.len();

View File

@ -10,3 +10,5 @@
#[no_mangle]
pub static foo: int = 3;
pub fn bar() {}

View File

@ -0,0 +1,19 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --test
//! Test that makes sure wrongly-typed bench functions aren't ignored
#[bench]
fn foo() { } //~ ERROR functions used as benches
#[bench]
fn bar(x: int, y: int) { } //~ ERROR functions used as benches

View File

@ -0,0 +1,17 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --test
//! Test that makes sure wrongly-typed bench functions are rejected
// error-pattern:expected &-ptr but found int
#[bench]
fn bar(x: int) { }

View File

@ -0,0 +1,26 @@
// 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.
// Test that duplicate methods in impls are not allowed
struct Foo;
trait Bar {
fn bar(&self) -> int;
}
impl Bar for Foo {
fn bar(&self) -> int {1}
fn bar(&self) -> int {2} //~ ERROR duplicate method
}
fn main() {
println!("{}", Foo.bar());
}

View File

@ -26,6 +26,13 @@ extern {
}
fn main() {
// It appears that the --as-needed flag to linkers will not pull in a dynamic
// library unless it satisfies a non weak undefined symbol. The 'other' crate
// is compiled as a dynamic library where it would only be used for a
// weak-symbol as part of an executable, so the dynamic library woudl be
// discarded. By adding and calling `other::bar`, we get around this problem.
other::bar();
assert!(!foo.is_null());
assert_eq!(unsafe { *foo }, 3);
assert!(something_that_should_never_exist.is_null());

View File

@ -0,0 +1,13 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This file has utf-8 BOM, it should be compiled normally without error.
pub fn main() {}