#
# First, start with one of these build targets:
#
-# * all - The default. Builds a complete, bootstrapped compiler.
+# * all - The default. Build a complete, bootstrapped compiler.
# `rustc` will be in `${target-triple}/stage2/bin/`. Run it
# directly from the build directory if you like. This also
# comes with docs in `doc/`.
#
# * check - Run the complete test suite
#
+# * clean - Clean the build repertory. It is advised to run this
+# command if you want to build Rust again, after an update
+# of the git repository.
+#
# * install - Install Rust. Note that installation is not necessary
# to use the compiler.
#
#
# </tips>
#
-# <nittygritty>
+# <nitty-gritty>
#
# # The Rust Build System
#
# libraries are managed and versioned without polluting the common
# areas of the filesystem.
#
-# General rust binaries may stil live in the host bin directory; they
+# General rust binaries may still live in the host bin directory; they
# will just link against the libraries in the target lib directory.
#
# Admittedly this is a little convoluted.
#
-# </nittygritty>
+# </nitty-gritty>
#
######################################################################
# $(1) is the name of the doc <section> in Makefile.in
# pick everything between tags | remove first line | remove last line
# | remove extra (?) line | strip leading `#` from lines
-SHOW_DOCS = $(Q)awk '/$(1)/,/<\/$(1)>/' $(S)/Makefile.in | sed '1d' | sed '$$d' | sed 's/^\# \?//'
+SHOW_DOCS = $(Q)awk '/<$(1)>/,/<\/$(1)>/' $(S)/Makefile.in | sed '1d' | sed '$$d' | sed 's/^\# \?//'
help:
$(call SHOW_DOCS,help)
-hot-tips:
- $(call SHOW_DOCS,hottips)
+tips:
+ $(call SHOW_DOCS,tips)
nitty-gritty:
- $(call SHOW_DOCS,nittygritty)
+ $(call SHOW_DOCS,nitty-gritty)
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
$(Q)find $(S)src/etc -name '*.py' \
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
+ $(Q)find $(S)src/doc -name '*.js' \
+ | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
+ $(Q)find $(S)src/etc -name '*.sh' \
+ | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
+ $(Q)find $(S)src/etc -name '*.pl' \
+ | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
+ $(Q)find $(S)src/etc -name '*.c' \
+ | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
+ $(Q)find $(S)src/etc -name '*.h' \
+ | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
$(Q)echo $(ALL_CS) \
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
$(Q)echo $(ALL_HS) \
-Subproject commit d4606f1818dd8dfeaa3e509cd1cbac4482c3513e
+Subproject commit f4b221571ce6f05714c1f1c6fa48f1393499989c
});
~~~
-Instead we can use a `SharedChan`, a type that allows a single
-`Chan` to be shared by multiple senders.
+Instead we can clone the `chan`, which allows for multiple senders.
~~~
# use std::task::spawn;
# fn some_expensive_computation(_i: uint) -> int { 42 }
~~~
-Here we transfer ownership of the channel into a new `SharedChan` value. Like
-`Chan`, `SharedChan` is a non-copyable, owned type (sometimes also referred to
-as an *affine* or *linear* type). Unlike with `Chan`, though, the programmer
-may duplicate a `SharedChan`, with the `clone()` method. A cloned
-`SharedChan` produces a new handle to the same channel, allowing multiple
-tasks to send data to a single port. Between `spawn`, `Chan` and
-`SharedChan`, we have enough tools to implement many useful concurrency
-patterns.
+Cloning a `Chan` produces a new handle to the same channel, allowing multiple
+tasks to send data to a single port. It also upgrades the channel internally in
+order to allow this functionality, which means that channels that are not
+cloned can avoid the overhead required to handle multiple senders. But this
+fact has no bearing on the channel's usage: the upgrade is transparent.
-Note that the above `SharedChan` example is somewhat contrived since
+Note that the above cloning example is somewhat contrived since
you could also simply use three `Chan` pairs, but it serves to
illustrate the point. For reference, written with multiple streams, it
might look like the example below.
+// Copyright (C) 2013 by Marijn Haverbeke <marijnh@gmail.com> and others
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
exports.htmlEscape = function(text) {
var replacements = {"<": "<", ">": ">",
"&": "&", "\"": """};
if (string == "\n")
accum.push("<br>");
else if (style)
- accum.push("<span class=\"cm-" + exports.htmlEscape(style) + "\">" + exports.htmlEscape(string) + "</span>");
+ accum.push("<span class=\"cm-" + exports.htmlEscape(style) + "\">" +
+ exports.htmlEscape(string) + "</span>");
else
accum.push(exports.htmlEscape(string));
}
+// Copyright (C) 2013 by Marijn Haverbeke <marijnh@gmail.com> and others
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
CodeMirror.defineMode("rust", function() {
var indentUnit = 4, altIndentUnit = 2;
var valKeywords = {
type = lexical.type, closing = firstChar == type;
if (type == "stat") return lexical.indented + indentUnit;
if (lexical.align) return lexical.column + (closing ? 0 : 1);
- return lexical.indented + (closing ? 0 : (lexical.info == "match" ? altIndentUnit : indentUnit));
+ return lexical.indented +
+ (closing ? 0 : (lexical.info == "match" ? altIndentUnit : indentUnit));
},
electricChars: "{}"
#!/usr/local/bin/node
+// 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.
+
/***
* Pandoc-style markdown preprocessor that drops extra directives
* included for running doc code, and that optionally, when
them. Owned closures are used in concurrent code, particularly
for spawning [tasks][tasks].
+Closures can be used to spawn tasks.
+A practical example of this pattern is found when using the `spawn` function,
+which starts a new task.
+
+~~~~
+use std::task::spawn;
+
+// proc is the closure which will be spawned.
+spawn(proc() {
+ debug!("I'm a new task")
+});
+~~~~
+
+> ***Note:*** If you want to see the output of `debug!` statements, you will need to turn on
+> `debug!` logging. To enable `debug!` logging, set the RUST_LOG environment
+> variable to the name of your crate, which, for a file named `foo.rs`, will be
+> `foo` (e.g., with bash, `export RUST_LOG=foo`).
+
## Closure compatibility
Rust closures have a convenient subtyping property: you can pass any kind of
> in small ways. At the moment they can be unsound in some
> scenarios, particularly with non-copyable types.
-## Do syntax
-
-The `do` expression makes it easier to call functions that take procedures
-as arguments.
-
-Consider this function that takes a procedure:
-
-~~~~
-fn call_it(op: proc(v: int)) {
- op(10)
-}
-~~~~
-
-As a caller, if we use a closure to provide the final operator
-argument, we can write it in a way that has a pleasant, block-like
-structure.
-
-~~~~
-# fn call_it(op: proc(v: int)) { }
-call_it(proc(n) {
- println!("{}", n);
-});
-~~~~
-
-A practical example of this pattern is found when using the `spawn` function,
-which starts a new task.
-
-~~~~
-use std::task::spawn;
-spawn(proc() {
- debug!("I'm a new task")
-});
-~~~~
-
-If you want to see the output of `debug!` statements, you will need to turn on
-`debug!` logging. To enable `debug!` logging, set the RUST_LOG environment
-variable to the name of your crate, which, for a file named `foo.rs`, will be
-`foo` (e.g., with bash, `export RUST_LOG=foo`).
-
# Methods
Methods are like functions except that they always begin with a special argument,
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+#
+# ignore-tidy-linelength
#
# usage : adb_run_wrapper [test dir - where test executables exist] [test executable]
#
#!/usr/bin/perl -w
+# 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.
my $file = $ARGV[0];
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+//
// This is a helper C program for generating required math constants
//
// Should only be required when porting to a different target architecture
+# 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 runs the test for emacs rust-mode.
# It must be possible to find emacs via PATH.
emacs -batch -l rust-mode.el -l rust-mode-tests.el -f ert-run-tests-batch-and-exit
+// 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 calculates the platform-variable portion of the libc module.
* Move code in here only as you discover it is platform-variable.
"""
exceptions = [
+ "doc/lib/codemirror-node.js", # MIT
+ "doc/lib/codemirror-rust.js", # MIT
"rt/rust_android_dummy.cpp", # BSD, chromium
"rt/rust_android_dummy.h", # BSD, chromium
"rt/isaac/randport.cpp", # public domain
#!/bin/sh
+# 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.
TARG_DIR=$1
PREFIX=$2
OS=`uname -s`
case $OS in
("Linux"|"FreeBSD")
- BIN_SUF=
- LIB_SUF=.so
- break
- ;;
+ BIN_SUF=
+ LIB_SUF=.so
+ break
+ ;;
("Darwin")
- BIN_SUF=
- LIB_SUF=.dylib
- break
- ;;
+ BIN_SUF=
+ LIB_SUF=.dylib
+ break
+ ;;
(*)
- BIN_SUF=.exe
- LIB_SUF=.dll
- LIB_DIR=bin
- LIB_PREFIX=
- break
- ;;
+ BIN_SUF=.exe
+ LIB_SUF=.dll
+ LIB_DIR=bin
+ LIB_PREFIX=
+ break
+ ;;
esac
if [ -z $PREFIX ]; then
+// 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.
+
#ifndef _FIX_CXXCONFIG_H
#define _FIX_CXXCONFIG_H 1
+// 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.
+
#ifndef _FIX_WINBASE_H
#define _FIX_WINBASE_H 1
+// 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.
+
#ifndef _FIX_WINSOCK2_H
#define _FIX_WINSOCK2_H 1
syn keyword rustTrait OrdIterator MutableDoubleEndedIterator ExactSize
syn keyword rustTrait Algebraic Trigonometric Exponential Hyperbolic
-syn keyword rustTrait Bitwise Bounded Integer Fractional Real RealExt
+syn keyword rustTrait Bitwise Bounded Integer
syn keyword rustTrait Num NumCast CheckedAdd CheckedSub CheckedMul CheckedDiv
syn keyword rustTrait Orderable Signed Unsigned Round
syn keyword rustTrait Primitive Int Float ToStrRadix ToPrimitive FromPrimitive
To encode using Encodable :
```rust
+extern crate extra;
extern crate serialize;
use extra::json;
use std::io;
```rust
+extern crate extra;
extern crate collections;
use extra::json;
}
```
-To decode a json string using `Decodable` trait :
+To decode a JSON string using `Decodable` trait :
```rust
+extern crate extra;
extern crate serialize;
use serialize::Decodable;
using the serialization API, using the derived serialization code.
```rust
+extern crate extra;
extern crate serialize;
use extra::json;
use serialize::{Encodable, Decodable};
{data_int: 1, data_str:~"toto", data_vector:~[2,3,4,5]};
let encoded_str: ~str = json::Encoder::str_encode(&to_encode_object);
- // To unserialize use the `extra::json::from_str` and `extra::json::Decoder`
+ // To deserialize use the `extra::json::from_str` and `extra::json::Decoder`
let json_object = extra::json::from_str(encoded_str);
let mut decoder = json::Decoder::new(json_object.unwrap());
## Using `ToJson`
-This example use the ToJson impl to unserialize the json string.
+This example use the ToJson impl to deserialize the JSON string.
Example of `ToJson` trait implementation for TestStruct1.
```rust
+extern crate extra;
extern crate serialize;
extern crate collections;
}
fn main() {
- // Seralization using our impl of to_json
+ // Serialization using our impl of to_json
let test2: TestStruct1 = TestStruct1 {data_int: 1, data_str:~"toto", data_vector:~[2,3,4,5]};
let tjson: json::Json = test2.to_json();
let json_str: ~str = tjson.to_str();
- // Unserialize like before.
+ // Deserialize like before.
let mut decoder = json::Decoder::new(json::from_str(json_str).unwrap());
// create the final object
// Benchmarking
-/// A function that is opaque to the optimiser, to allow benchmarks to
+/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// A flag to tell the scheduler loop it needs to do some stealing
/// in order to introduce randomness as part of a yield
steal_for_yield: bool,
- /// Bookeeping for the number of tasks which are currently running around
+ /// Bookkeeping for the number of tasks which are currently running around
/// inside this pool of schedulers
task_state: TaskState,
else {
let fp_vec = vec::from_buf(
fp_buf, wcslen(fp_buf) as uint);
- let fp_str = str::from_utf16(fp_vec);
+ let fp_trimmed = str::truncate_utf16_at_nul(fp_vec);
+ let fp_str = str::from_utf16(fp_trimmed)
+ .expect("rust_list_dir_wfd_fp_buf returned invalid UTF-16");
paths.push(Path::new(fp_str));
}
more_files = FindNextFileW(find_handle, wfd_ptr as HANDLE);
#[path = "timer_win32.rs"]
pub mod timer;
+#[cfg(unix)]
+#[path = "pipe_unix.rs"]
+pub mod pipe;
+
+#[cfg(windows)]
+#[path = "pipe_win32.rs"]
+pub mod pipe;
+
mod timer_helper;
pub type IoResult<T> = Result<T, IoError>;
fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
match errno {
libc::EOF => (io::EndOfFile, "end of file"),
+ libc::ERROR_NO_DATA => (io::BrokenPipe, "the pipe is being closed"),
+ libc::ERROR_FILE_NOT_FOUND => (io::FileNotFound, "file not found"),
+ libc::ERROR_INVALID_NAME => (io::InvalidInput, "invalid file name"),
libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"),
libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"),
libc::WSAEACCES => (io::PermissionDenied, "permission denied"),
libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"),
libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"),
+ libc::ERROR_BROKEN_PIPE => (io::BrokenPipe, "the pipe has ended"),
x => {
debug!("ignoring {}: {}", x, os::last_os_error());
libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"),
libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
libc::EADDRINUSE => (io::ConnectionRefused, "address in use"),
+ libc::ENOENT => (io::FileNotFound, "no such file or directory"),
// These two constants can have the same value on some systems, but
// different values on others, so we can't use a match clause
fn udp_bind(&mut self, addr: SocketAddr) -> IoResult<~RtioUdpSocket> {
net::UdpSocket::bind(addr).map(|u| ~u as ~RtioUdpSocket)
}
- fn unix_bind(&mut self, _path: &CString) -> IoResult<~RtioUnixListener> {
- Err(unimpl())
+ fn unix_bind(&mut self, path: &CString) -> IoResult<~RtioUnixListener> {
+ pipe::UnixListener::bind(path).map(|s| ~s as ~RtioUnixListener)
}
- fn unix_connect(&mut self, _path: &CString) -> IoResult<~RtioPipe> {
- Err(unimpl())
+ fn unix_connect(&mut self, path: &CString) -> IoResult<~RtioPipe> {
+ pipe::UnixStream::connect(path).map(|s| ~s as ~RtioPipe)
}
fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
hint: Option<ai::Hint>) -> IoResult<~[ai::Info]> {
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::c_str::CString;
+use std::cast;
+use std::io;
+use std::libc;
+use std::mem;
+use std::rt::rtio;
+use std::sync::arc::UnsafeArc;
+use std::unstable::intrinsics;
+
+use super::{IoResult, retry};
+use super::file::{keep_going, fd_t};
+
+fn unix_socket(ty: libc::c_int) -> IoResult<fd_t> {
+ match unsafe { libc::socket(libc::AF_UNIX, ty, 0) } {
+ -1 => Err(super::last_error()),
+ fd => Ok(fd)
+ }
+}
+
+fn addr_to_sockaddr_un(addr: &CString) -> IoResult<(libc::sockaddr_storage, uint)> {
+ // the sun_path length is limited to SUN_LEN (with null)
+ assert!(mem::size_of::<libc::sockaddr_storage>() >=
+ mem::size_of::<libc::sockaddr_un>());
+ let mut storage: libc::sockaddr_storage = unsafe { intrinsics::init() };
+ let s: &mut libc::sockaddr_un = unsafe { cast::transmute(&mut storage) };
+
+ let len = addr.len();
+ if len > s.sun_path.len() - 1 {
+ return Err(io::IoError {
+ kind: io::InvalidInput,
+ desc: "path must be smaller than SUN_LEN",
+ detail: None,
+ })
+ }
+ s.sun_family = libc::AF_UNIX as libc::sa_family_t;
+ for (slot, value) in s.sun_path.mut_iter().zip(addr.iter()) {
+ *slot = value;
+ }
+
+ // count the null terminator
+ let len = mem::size_of::<libc::sa_family_t>() + len + 1;
+ return Ok((storage, len));
+}
+
+fn sockaddr_to_unix(storage: &libc::sockaddr_storage,
+ len: uint) -> IoResult<CString> {
+ match storage.ss_family as libc::c_int {
+ libc::AF_UNIX => {
+ assert!(len as uint <= mem::size_of::<libc::sockaddr_un>());
+ let storage: &libc::sockaddr_un = unsafe {
+ cast::transmute(storage)
+ };
+ unsafe {
+ Ok(CString::new(storage.sun_path.as_ptr(), false).clone())
+ }
+ }
+ _ => Err(io::standard_error(io::InvalidInput))
+ }
+}
+
+struct Inner {
+ fd: fd_t,
+}
+
+impl Drop for Inner {
+ fn drop(&mut self) { unsafe { let _ = libc::close(self.fd); } }
+}
+
+fn connect(addr: &CString, ty: libc::c_int) -> IoResult<Inner> {
+ let (addr, len) = if_ok!(addr_to_sockaddr_un(addr));
+ let inner = Inner { fd: if_ok!(unix_socket(ty)) };
+ let addrp = &addr as *libc::sockaddr_storage;
+ match retry(|| unsafe {
+ libc::connect(inner.fd, addrp as *libc::sockaddr,
+ len as libc::socklen_t)
+ }) {
+ -1 => Err(super::last_error()),
+ _ => Ok(inner)
+ }
+}
+
+fn bind(addr: &CString, ty: libc::c_int) -> IoResult<Inner> {
+ let (addr, len) = if_ok!(addr_to_sockaddr_un(addr));
+ let inner = Inner { fd: if_ok!(unix_socket(ty)) };
+ let addrp = &addr as *libc::sockaddr_storage;
+ match unsafe {
+ libc::bind(inner.fd, addrp as *libc::sockaddr, len as libc::socklen_t)
+ } {
+ -1 => Err(super::last_error()),
+ _ => Ok(inner)
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixStream {
+ priv inner: UnsafeArc<Inner>,
+}
+
+impl UnixStream {
+ pub fn connect(addr: &CString) -> IoResult<UnixStream> {
+ connect(addr, libc::SOCK_STREAM).map(|inner| {
+ UnixStream { inner: UnsafeArc::new(inner) }
+ })
+ }
+
+ fn fd(&self) -> fd_t { unsafe { (*self.inner.get()).fd } }
+}
+
+impl rtio::RtioPipe for UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+ let ret = retry(|| unsafe {
+ libc::recv(self.fd(),
+ buf.as_ptr() as *mut libc::c_void,
+ buf.len() as libc::size_t,
+ 0) as libc::c_int
+ });
+ if ret == 0 {
+ Err(io::standard_error(io::EndOfFile))
+ } else if ret < 0 {
+ Err(super::last_error())
+ } else {
+ Ok(ret as uint)
+ }
+ }
+
+ fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+ let ret = keep_going(buf, |buf, len| unsafe {
+ libc::send(self.fd(),
+ buf as *mut libc::c_void,
+ len as libc::size_t,
+ 0) as i64
+ });
+ if ret < 0 {
+ Err(super::last_error())
+ } else {
+ Ok(())
+ }
+ }
+
+ fn clone(&self) -> ~rtio::RtioPipe {
+ ~UnixStream { inner: self.inner.clone() } as ~rtio::RtioPipe
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Datagram
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixDatagram {
+ priv inner: UnsafeArc<Inner>,
+}
+
+impl UnixDatagram {
+ pub fn connect(addr: &CString) -> IoResult<UnixDatagram> {
+ connect(addr, libc::SOCK_DGRAM).map(|inner| {
+ UnixDatagram { inner: UnsafeArc::new(inner) }
+ })
+ }
+
+ pub fn bind(addr: &CString) -> IoResult<UnixDatagram> {
+ bind(addr, libc::SOCK_DGRAM).map(|inner| {
+ UnixDatagram { inner: UnsafeArc::new(inner) }
+ })
+ }
+
+ fn fd(&self) -> fd_t { unsafe { (*self.inner.get()).fd } }
+
+ pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, CString)> {
+ let mut storage: libc::sockaddr_storage = unsafe { intrinsics::init() };
+ let storagep = &mut storage as *mut libc::sockaddr_storage;
+ let mut addrlen: libc::socklen_t =
+ mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
+ let ret = retry(|| unsafe {
+ libc::recvfrom(self.fd(),
+ buf.as_ptr() as *mut libc::c_void,
+ buf.len() as libc::size_t,
+ 0,
+ storagep as *mut libc::sockaddr,
+ &mut addrlen) as libc::c_int
+ });
+ if ret < 0 { return Err(super::last_error()) }
+ sockaddr_to_unix(&storage, addrlen as uint).and_then(|addr| {
+ Ok((ret as uint, addr))
+ })
+ }
+
+ pub fn sendto(&mut self, buf: &[u8], dst: &CString) -> IoResult<()> {
+ let (dst, len) = if_ok!(addr_to_sockaddr_un(dst));
+ let dstp = &dst as *libc::sockaddr_storage;
+ let ret = retry(|| unsafe {
+ libc::sendto(self.fd(),
+ buf.as_ptr() as *libc::c_void,
+ buf.len() as libc::size_t,
+ 0,
+ dstp as *libc::sockaddr,
+ len as libc::socklen_t) as libc::c_int
+ });
+ match ret {
+ -1 => Err(super::last_error()),
+ n if n as uint != buf.len() => {
+ Err(io::IoError {
+ kind: io::OtherIoError,
+ desc: "couldn't send entire packet at once",
+ detail: None,
+ })
+ }
+ _ => Ok(())
+ }
+ }
+
+ pub fn clone(&mut self) -> UnixDatagram {
+ UnixDatagram { inner: self.inner.clone() }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Listener
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixListener {
+ priv inner: Inner,
+}
+
+impl UnixListener {
+ pub fn bind(addr: &CString) -> IoResult<UnixListener> {
+ bind(addr, libc::SOCK_STREAM).map(|fd| UnixListener { inner: fd })
+ }
+
+ fn fd(&self) -> fd_t { self.inner.fd }
+
+ pub fn native_listen(self, backlog: int) -> IoResult<UnixAcceptor> {
+ match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } {
+ -1 => Err(super::last_error()),
+ _ => Ok(UnixAcceptor { listener: self })
+ }
+ }
+}
+
+impl rtio::RtioUnixListener for UnixListener {
+ fn listen(~self) -> IoResult<~rtio::RtioUnixAcceptor> {
+ self.native_listen(128).map(|a| ~a as ~rtio::RtioUnixAcceptor)
+ }
+}
+
+pub struct UnixAcceptor {
+ priv listener: UnixListener,
+}
+
+impl UnixAcceptor {
+ fn fd(&self) -> fd_t { self.listener.fd() }
+
+ pub fn native_accept(&mut self) -> IoResult<UnixStream> {
+ let mut storage: libc::sockaddr_storage = unsafe { intrinsics::init() };
+ let storagep = &mut storage as *mut libc::sockaddr_storage;
+ let size = mem::size_of::<libc::sockaddr_storage>();
+ let mut size = size as libc::socklen_t;
+ match retry(|| unsafe {
+ libc::accept(self.fd(),
+ storagep as *mut libc::sockaddr,
+ &mut size as *mut libc::socklen_t) as libc::c_int
+ }) {
+ -1 => Err(super::last_error()),
+ fd => Ok(UnixStream { inner: UnsafeArc::new(Inner { fd: fd }) })
+ }
+ }
+}
+
+impl rtio::RtioUnixAcceptor for UnixAcceptor {
+ fn accept(&mut self) -> IoResult<~rtio::RtioPipe> {
+ self.native_accept().map(|s| ~s as ~rtio::RtioPipe)
+ }
+}
--- /dev/null
+// 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.
+
+//! Named pipes implementation for windows
+//!
+//! If are unfortunate enough to be reading this code, I would like to first
+//! apologize. This was my first encounter with windows named pipes, and it
+//! didn't exactly turn out very cleanly. If you, too, are new to named pipes,
+//! read on as I'll try to explain some fun things that I ran into.
+//!
+//! # Unix pipes vs Named pipes
+//!
+//! As with everything else, named pipes on windows are pretty different from
+//! unix pipes on unix. On unix, you use one "server pipe" to accept new client
+//! pipes. So long as this server pipe is active, new children pipes can
+//! connect. On windows, you instead have a number of "server pipes", and each
+//! of these server pipes can throughout their lifetime be attached to a client
+//! or not. Once attached to a client, a server pipe may then disconnect at a
+//! later date.
+//!
+//! # Accepting clients
+//!
+//! As with most other I/O interfaces, our Listener/Acceptor/Stream interfaces
+//! are built around the unix flavors. This means that we have one "server
+//! pipe" to which many clients can connect. In order to make this compatible
+//! with the windows model, each connected client consumes ownership of a server
+//! pipe, and then a new server pipe is created for the next client.
+//!
+//! Note that the server pipes attached to clients are never given back to the
+//! listener for recycling. This could possibly be implemented with a channel so
+//! the listener half can re-use server pipes, but for now I err'd on the simple
+//! side of things. Each stream accepted by a listener will destroy the server
+//! pipe after the stream is dropped.
+//!
+//! This model ends up having a small race or two, and you can find more details
+//! on the `native_accept` method.
+//!
+//! # Simultaneous reads and writes
+//!
+//! In testing, I found that two simultaneous writes and two simultaneous reads
+//! on a pipe ended up working out just fine, but problems were encountered when
+//! a read was executed simultaneously with a write. After some googling around,
+//! it sounded like named pipes just weren't built for this kind of interaction,
+//! and the suggested solution was to use overlapped I/O.
+//!
+//! I don't realy know what overlapped I/O is, but my basic understanding after
+//! reading about it is that you have an external Event which is used to signal
+//! I/O completion, passed around in some OVERLAPPED structures. As to what this
+//! is, I'm not exactly sure.
+//!
+//! This problem implies that all named pipes are created with the
+//! FILE_FLAG_OVERLAPPED option. This means that all of their I/O is
+//! asynchronous. Each I/O operation has an associated OVERLAPPED structure, and
+//! inside of this structure is a HANDLE from CreateEvent. After the I/O is
+//! determined to be pending (may complete in the future), the
+//! GetOverlappedResult function is used to block on the event, waiting for the
+//! I/O to finish.
+//!
+//! This scheme ended up working well enough. There were two snags that I ran
+//! into, however:
+//!
+//! * Each UnixStream instance needs its own read/write events to wait on. These
+//! can't be shared among clones of the same stream because the documentation
+//! states that it unsets the event when the I/O is started (would possibly
+//! corrupt other events simultaneously waiting). For convenience's sake,
+//! these events are lazily initialized.
+//!
+//! * Each server pipe needs to be created with FILE_FLAG_OVERLAPPED in addition
+//! to all pipes created through `connect`. Notably this means that the
+//! ConnectNamedPipe function is nonblocking, implying that the Listener needs
+//! to have yet another event to do the actual blocking.
+//!
+//! # Conclusion
+//!
+//! The conclusion here is that I probably don't know the best way to work with
+//! windows named pipes, but the solution here seems to work well enough to get
+//! the test suite passing (the suite is in libstd), and that's good enough for
+//! me!
+
+use std::c_str::CString;
+use std::libc;
+use std::os::win32::as_utf16_p;
+use std::ptr;
+use std::rt::rtio;
+use std::sync::arc::UnsafeArc;
+use std::unstable::intrinsics;
+
+use super::IoResult;
+
+struct Event(libc::HANDLE);
+
+impl Event {
+ fn new(manual_reset: bool, initial_state: bool) -> IoResult<Event> {
+ let event = unsafe {
+ libc::CreateEventW(ptr::mut_null(),
+ manual_reset as libc::BOOL,
+ initial_state as libc::BOOL,
+ ptr::null())
+ };
+ if event as uint == 0 {
+ Err(super::last_error())
+ } else {
+ Ok(Event(event))
+ }
+ }
+
+ fn handle(&self) -> libc::HANDLE { let Event(handle) = *self; handle }
+}
+
+impl Drop for Event {
+ fn drop(&mut self) {
+ unsafe { let _ = libc::CloseHandle(self.handle()); }
+ }
+}
+
+struct Inner {
+ handle: libc::HANDLE,
+}
+
+impl Drop for Inner {
+ fn drop(&mut self) {
+ unsafe {
+ let _ = libc::FlushFileBuffers(self.handle);
+ let _ = libc::CloseHandle(self.handle);
+ }
+ }
+}
+
+unsafe fn pipe(name: *u16, init: bool) -> libc::HANDLE {
+ libc::CreateNamedPipeW(
+ name,
+ libc::PIPE_ACCESS_DUPLEX |
+ if init {libc::FILE_FLAG_FIRST_PIPE_INSTANCE} else {0} |
+ libc::FILE_FLAG_OVERLAPPED,
+ libc::PIPE_TYPE_BYTE | libc::PIPE_READMODE_BYTE |
+ libc::PIPE_WAIT,
+ libc::PIPE_UNLIMITED_INSTANCES,
+ 65536,
+ 65536,
+ 0,
+ ptr::mut_null()
+ )
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixStream {
+ priv inner: UnsafeArc<Inner>,
+ priv write: Option<Event>,
+ priv read: Option<Event>,
+}
+
+impl UnixStream {
+ fn try_connect(p: *u16) -> Option<libc::HANDLE> {
+ // Note that most of this is lifted from the libuv implementation.
+ // The idea is that if we fail to open a pipe in read/write mode
+ // that we try afterwards in just read or just write
+ let mut result = unsafe {
+ libc::CreateFileW(p,
+ libc::GENERIC_READ | libc::GENERIC_WRITE,
+ 0,
+ ptr::mut_null(),
+ libc::OPEN_EXISTING,
+ libc::FILE_FLAG_OVERLAPPED,
+ ptr::mut_null())
+ };
+ if result != libc::INVALID_HANDLE_VALUE as libc::HANDLE {
+ return Some(result)
+ }
+
+ let err = unsafe { libc::GetLastError() };
+ if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
+ result = unsafe {
+ libc::CreateFileW(p,
+ libc::GENERIC_READ | libc::FILE_WRITE_ATTRIBUTES,
+ 0,
+ ptr::mut_null(),
+ libc::OPEN_EXISTING,
+ libc::FILE_FLAG_OVERLAPPED,
+ ptr::mut_null())
+ };
+ if result != libc::INVALID_HANDLE_VALUE as libc::HANDLE {
+ return Some(result)
+ }
+ }
+ let err = unsafe { libc::GetLastError() };
+ if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
+ result = unsafe {
+ libc::CreateFileW(p,
+ libc::GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES,
+ 0,
+ ptr::mut_null(),
+ libc::OPEN_EXISTING,
+ libc::FILE_FLAG_OVERLAPPED,
+ ptr::mut_null())
+ };
+ if result != libc::INVALID_HANDLE_VALUE as libc::HANDLE {
+ return Some(result)
+ }
+ }
+ None
+ }
+
+ pub fn connect(addr: &CString) -> IoResult<UnixStream> {
+ as_utf16_p(addr.as_str().unwrap(), |p| {
+ loop {
+ match UnixStream::try_connect(p) {
+ Some(handle) => {
+ let inner = Inner { handle: handle };
+ let mut mode = libc::PIPE_TYPE_BYTE |
+ libc::PIPE_READMODE_BYTE |
+ libc::PIPE_WAIT;
+ let ret = unsafe {
+ libc::SetNamedPipeHandleState(inner.handle,
+ &mut mode,
+ ptr::mut_null(),
+ ptr::mut_null())
+ };
+ return if ret == 0 {
+ Err(super::last_error())
+ } else {
+ Ok(UnixStream {
+ inner: UnsafeArc::new(inner),
+ read: None,
+ write: None,
+ })
+ }
+ }
+ None => {}
+ }
+
+ // On windows, if you fail to connect, you may need to call the
+ // `WaitNamedPipe` function, and this is indicated with an error
+ // code of ERROR_PIPE_BUSY.
+ let code = unsafe { libc::GetLastError() };
+ if code as int != libc::ERROR_PIPE_BUSY as int {
+ return Err(super::last_error())
+ }
+
+ // An example I found on microsoft's website used 20 seconds,
+ // libuv uses 30 seconds, hence we make the obvious choice of
+ // waiting for 25 seconds.
+ if unsafe { libc::WaitNamedPipeW(p, 25000) } == 0 {
+ return Err(super::last_error())
+ }
+ }
+ })
+ }
+
+ fn handle(&self) -> libc::HANDLE { unsafe { (*self.inner.get()).handle } }
+}
+
+impl rtio::RtioPipe for UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+ if self.read.is_none() {
+ self.read = Some(if_ok!(Event::new(true, false)));
+ }
+
+ let mut bytes_read = 0;
+ let mut overlapped: libc::OVERLAPPED = unsafe { intrinsics::init() };
+ overlapped.hEvent = self.read.get_ref().handle();
+
+ let ret = unsafe {
+ libc::ReadFile(self.handle(),
+ buf.as_ptr() as libc::LPVOID,
+ buf.len() as libc::DWORD,
+ &mut bytes_read,
+ &mut overlapped)
+ };
+ if ret == 0 {
+ let err = unsafe { libc::GetLastError() };
+ if err == libc::ERROR_IO_PENDING as libc::DWORD {
+ let ret = unsafe {
+ libc::GetOverlappedResult(self.handle(),
+ &mut overlapped,
+ &mut bytes_read,
+ libc::TRUE)
+ };
+ if ret == 0 {
+ return Err(super::last_error())
+ }
+ } else {
+ return Err(super::last_error())
+ }
+ }
+
+ Ok(bytes_read as uint)
+ }
+
+ fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+ if self.write.is_none() {
+ self.write = Some(if_ok!(Event::new(true, false)));
+ }
+
+ let mut offset = 0;
+ let mut overlapped: libc::OVERLAPPED = unsafe { intrinsics::init() };
+ overlapped.hEvent = self.write.get_ref().handle();
+
+ while offset < buf.len() {
+ let mut bytes_written = 0;
+ let ret = unsafe {
+ libc::WriteFile(self.handle(),
+ buf.slice_from(offset).as_ptr() as libc::LPVOID,
+ (buf.len() - offset) as libc::DWORD,
+ &mut bytes_written,
+ &mut overlapped)
+ };
+ if ret == 0 {
+ let err = unsafe { libc::GetLastError() };
+ if err == libc::ERROR_IO_PENDING as libc::DWORD {
+ let ret = unsafe {
+ libc::GetOverlappedResult(self.handle(),
+ &mut overlapped,
+ &mut bytes_written,
+ libc::TRUE)
+ };
+ if ret == 0 {
+ return Err(super::last_error())
+ }
+ } else {
+ return Err(super::last_error())
+ }
+ }
+ offset += bytes_written as uint;
+ }
+ Ok(())
+ }
+
+ fn clone(&self) -> ~rtio::RtioPipe {
+ ~UnixStream {
+ inner: self.inner.clone(),
+ read: None,
+ write: None,
+ } as ~rtio::RtioPipe
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Listener
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixListener {
+ priv handle: libc::HANDLE,
+ priv name: CString,
+}
+
+impl UnixListener {
+ pub fn bind(addr: &CString) -> IoResult<UnixListener> {
+ // Although we technically don't need the pipe until much later, we
+ // create the initial handle up front to test the validity of the name
+ // and such.
+ as_utf16_p(addr.as_str().unwrap(), |p| {
+ let ret = unsafe { pipe(p, true) };
+ if ret == libc::INVALID_HANDLE_VALUE as libc::HANDLE {
+ Err(super::last_error())
+ } else {
+ Ok(UnixListener { handle: ret, name: addr.clone() })
+ }
+ })
+ }
+
+ pub fn native_listen(self) -> IoResult<UnixAcceptor> {
+ Ok(UnixAcceptor {
+ listener: self,
+ event: if_ok!(Event::new(true, false)),
+ })
+ }
+}
+
+impl Drop for UnixListener {
+ fn drop(&mut self) {
+ unsafe { let _ = libc::CloseHandle(self.handle); }
+ }
+}
+
+impl rtio::RtioUnixListener for UnixListener {
+ fn listen(~self) -> IoResult<~rtio::RtioUnixAcceptor> {
+ self.native_listen().map(|a| ~a as ~rtio::RtioUnixAcceptor)
+ }
+}
+
+pub struct UnixAcceptor {
+ priv listener: UnixListener,
+ priv event: Event,
+}
+
+impl UnixAcceptor {
+ pub fn native_accept(&mut self) -> IoResult<UnixStream> {
+ // This function has some funky implementation details when working with
+ // unix pipes. On windows, each server named pipe handle can be
+ // connected to a one or zero clients. To the best of my knowledge, a
+ // named server is considered active and present if there exists at
+ // least one server named pipe for it.
+ //
+ // The model of this function is to take the current known server
+ // handle, connect a client to it, and then transfer ownership to the
+ // UnixStream instance. The next time accept() is invoked, it'll need a
+ // different server handle to connect a client to.
+ //
+ // Note that there is a possible race here. Once our server pipe is
+ // handed off to a `UnixStream` object, the stream could be closed,
+ // meaning that there would be no active server pipes, hence even though
+ // we have a valid `UnixAcceptor`, no one can connect to it. For this
+ // reason, we generate the next accept call's server pipe at the end of
+ // this function call.
+ //
+ // This provides us an invariant that we always have at least one server
+ // connection open at a time, meaning that all connects to this acceptor
+ // should succeed while this is active.
+ //
+ // The actual implementation of doing this is a little tricky. Once a
+ // server pipe is created, a client can connect to it at any time. I
+ // assume that which server a client connects to is nondeterministic, so
+ // we also need to guarantee that the only server able to be connected
+ // to is the one that we're calling ConnectNamedPipe on. This means that
+ // we have to create the second server pipe *after* we've already
+ // accepted a connection. In order to at least somewhat gracefully
+ // handle errors, this means that if the second server pipe creation
+ // fails that we disconnect the connected client and then just keep
+ // using the original server pipe.
+ let handle = self.listener.handle;
+
+ // Once we've got a "server handle", we need to wait for a client to
+ // connect. The ConnectNamedPipe function will block this thread until
+ // someone on the other end connects. This function can "fail" if a
+ // client connects after we created the pipe but before we got down
+ // here. Thanks windows.
+ let mut overlapped: libc::OVERLAPPED = unsafe { intrinsics::init() };
+ overlapped.hEvent = self.event.handle();
+ if unsafe { libc::ConnectNamedPipe(handle, &mut overlapped) == 0 } {
+ let mut err = unsafe { libc::GetLastError() };
+ if err == libc::ERROR_IO_PENDING as libc::DWORD {
+ let ret = unsafe {
+ let mut transfer = 0;
+ libc::GetOverlappedResult(handle,
+ &mut overlapped,
+ &mut transfer,
+ libc::TRUE)
+ };
+ if ret == 0 {
+ err = unsafe { libc::GetLastError() };
+ } else {
+ // we succeeded, bypass the check below
+ err = libc::ERROR_PIPE_CONNECTED as libc::DWORD;
+ }
+ }
+ if err != libc::ERROR_PIPE_CONNECTED as libc::DWORD {
+ return Err(super::last_error())
+ }
+ }
+
+ // Now that we've got a connected client to our handle, we need to
+ // create a second server pipe. If this fails, we disconnect the
+ // connected client and return an error (see comments above).
+ let new_handle = as_utf16_p(self.listener.name.as_str().unwrap(), |p| {
+ unsafe { pipe(p, false) }
+ });
+ if new_handle == libc::INVALID_HANDLE_VALUE as libc::HANDLE {
+ let ret = Err(super::last_error());
+ // If our disconnection fails, then there's not really a whole lot
+ // that we can do, so fail the task.
+ let err = unsafe { libc::DisconnectNamedPipe(handle) };
+ assert!(err != 0);
+ return ret;
+ } else {
+ self.listener.handle = new_handle;
+ }
+
+ // Transfer ownership of our handle into this stream
+ Ok(UnixStream {
+ inner: UnsafeArc::new(Inner { handle: handle }),
+ read: None,
+ write: None,
+ })
+ }
+}
+
+impl rtio::RtioUnixAcceptor for UnixAcceptor {
+ fn accept(&mut self) -> IoResult<~rtio::RtioPipe> {
+ self.native_accept().map(|s| ~s as ~rtio::RtioPipe)
+ }
+}
+
}
}
-impl<T: Clone + Real> Cmplx<T> {
+impl<T: Clone + Float> Cmplx<T> {
/// Calculate |self|
#[inline]
pub fn norm(&self) -> T {
}
}
-impl<T: Clone + Real> Cmplx<T> {
+impl<T: Clone + Float> Cmplx<T> {
/// Calculate the principal Arg of self.
#[inline]
pub fn arg(&self) -> T {
#[allow(non_uppercase_statics)];
use super::{Complex64, Cmplx};
- use std::num::{Zero,One,Real};
+ use std::num::{Zero,One,Float};
pub static _0_0i : Complex64 = Cmplx { re: 0.0, im: 0.0 };
pub static _1_0i : Complex64 = Cmplx { re: 1.0, im: 0.0 };
assert!((c.arg() - arg).abs() < 1.0e-6)
}
test(_1_0i, 0.0);
- test(_1_1i, 0.25 * Real::pi());
- test(_neg1_1i, 0.75 * Real::pi());
- test(_05_05i, 0.25 * Real::pi());
+ test(_1_1i, 0.25 * Float::pi());
+ test(_neg1_1i, 0.75 * Float::pi());
+ test(_05_05i, 0.25 * Float::pi());
}
#[test]
if_ok!(fs::rename(file, &new_filename));
inputs.push(new_filename);
}
+ if inputs.len() == 0 { return Ok(()) }
// Finally, add all the renamed files to this archive
let mut args = ~[&self.dst];
/// reexporting a public struct doesn't inline the doc).
pub type PublicItems = HashSet<ast::NodeId>;
+/// Result of a checking operation - None => no errors were found. Some => an
+/// error and contains the span and message for reporting that error and
+/// optionally the same for a note about the error.
+type CheckResult = Option<(Span, ~str, Option<(Span, ~str)>)>;
+
////////////////////////////////////////////////////////////////////////////////
/// The parent visitor, used to determine what's the parent of what (node-wise)
////////////////////////////////////////////////////////////////////////////////
}
}
- /// Guarantee that a particular definition is public, possibly emitting an
- /// error message if it's not.
+ fn report_error(&self, result: CheckResult) -> bool {
+ match result {
+ None => true,
+ Some((span, msg, note)) => {
+ self.tcx.sess.span_err(span, msg);
+ match note {
+ Some((span, msg)) => self.tcx.sess.span_note(span, msg),
+ None => {},
+ }
+ false
+ },
+ }
+ }
+
+ /// Guarantee that a particular definition is public. Returns a CheckResult
+ /// which contains any errors found. These can be reported using `report_error`.
+ /// If the result is `None`, no errors were found.
fn ensure_public(&self, span: Span, to_check: ast::DefId,
- source_did: Option<ast::DefId>, msg: &str) -> bool {
+ source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
match self.def_privacy(to_check) {
- ExternallyDenied => {
- self.tcx.sess.span_err(span, format!("{} is private", msg))
- }
+ ExternallyDenied => Some((span, format!("{} is private", msg), None)),
DisallowedBy(id) => {
- if id == source_did.unwrap_or(to_check).node {
- self.tcx.sess.span_err(span, format!("{} is private", msg));
- return false;
+ let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
+ return Some((span, format!("{} is private", msg), None));
} else {
- self.tcx.sess.span_err(span, format!("{} is inaccessible",
- msg));
- }
+ (span, format!("{} is inaccessible", msg))
+ };
match self.tcx.map.find(id) {
Some(ast_map::NodeItem(item)) => {
let desc = match item.node {
ast::ItemMod(..) => "module",
ast::ItemTrait(..) => "trait",
- _ => return false,
+ _ => return Some((err_span, err_msg, None)),
};
let msg = format!("{} `{}` is private",
desc,
token::get_ident(item.ident));
- self.tcx.sess.span_note(span, msg);
- }
- Some(..) | None => {}
+ Some((err_span, err_msg, Some((span, msg))))
+ },
+ _ => Some((err_span, err_msg, None)),
}
- }
- Allowable => return true
+ },
+ Allowable => None,
}
- return false;
}
// Checks that a field is in scope.
let method_id = ty::method(self.tcx, method_id).provided_source
.unwrap_or(method_id);
- self.ensure_public(span,
- method_id,
- None,
- format!("method `{}`", token::get_ident(name)));
+ let string = token::get_ident(name);
+ self.report_error(self.ensure_public(span,
+ method_id,
+ None,
+ format!("method `{}`", string)));
}
// Checks that a path is in scope.
fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) {
debug!("privacy - path {}", self.nodestr(path_id));
let def_map = self.tcx.def_map.borrow();
- let def = def_map.get().get_copy(&path_id);
+ let orig_def = def_map.get().get_copy(&path_id);
let ck = |tyname: &str| {
- let origdid = def_id_of_def(def);
+ let ck_public = |def: ast::DefId| {
+ let name = token::get_ident(path.segments
+ .last()
+ .unwrap()
+ .identifier);
+ let origdid = def_id_of_def(orig_def);
+ self.ensure_public(span,
+ def,
+ Some(origdid),
+ format!("{} `{}`",
+ tyname,
+ name))
+ };
+
match *self.last_private_map.get(&path_id) {
- resolve::AllPublic => {},
- resolve::DependsOn(def) => {
- let name = token::get_ident(path.segments
- .last()
- .unwrap()
- .identifier);
- self.ensure_public(span,
- def,
- Some(origdid),
- format!("{} `{}`",
- tyname, name));
- }
+ resolve::LastMod(resolve::AllPublic) => {},
+ resolve::LastMod(resolve::DependsOn(def)) => {
+ self.report_error(ck_public(def));
+ },
+ resolve::LastImport{value_priv: value_priv,
+ value_used: check_value,
+ type_priv: type_priv,
+ type_used: check_type} => {
+ // This dance with found_error is because we don't want to report
+ // a privacy error twice for the same directive.
+ let found_error = match (type_priv, check_type) {
+ (Some(resolve::DependsOn(def)), resolve::Used) => {
+ !self.report_error(ck_public(def))
+ },
+ _ => false,
+ };
+ if !found_error {
+ match (value_priv, check_value) {
+ (Some(resolve::DependsOn(def)), resolve::Used) => {
+ self.report_error(ck_public(def));
+ },
+ _ => {},
+ }
+ }
+ // If an import is not used in either namespace, we still want to check
+ // that it could be legal. Therefore we check in both namespaces and only
+ // report an error if both would be illegal. We only report one error,
+ // even if it is illegal to import from both namespaces.
+ match (value_priv, check_value, type_priv, check_type) {
+ (Some(p), resolve::Unused, None, _) |
+ (None, _, Some(p), resolve::Unused) => {
+ let p = match p {
+ resolve::AllPublic => None,
+ resolve::DependsOn(def) => ck_public(def),
+ };
+ if p.is_some() {
+ self.report_error(p);
+ }
+ },
+ (Some(v), resolve::Unused, Some(t), resolve::Unused) => {
+ let v = match v {
+ resolve::AllPublic => None,
+ resolve::DependsOn(def) => ck_public(def),
+ };
+ let t = match t {
+ resolve::AllPublic => None,
+ resolve::DependsOn(def) => ck_public(def),
+ };
+ match (v, t) {
+ (Some(_), Some(t)) => {
+ self.report_error(Some(t));
+ },
+ _ => {},
+ }
+ },
+ _ => {},
+ }
+ },
}
};
+ // FIXME(#12334) Imports can refer to definitions in both the type and
+ // value namespaces. The privacy information is aware of this, but the
+ // def map is not. Therefore the names we work out below will not always
+ // be accurate and we can get slightly wonky error messages (but type
+ // checking is always correct).
let def_map = self.tcx.def_map.borrow();
match def_map.get().get_copy(&path_id) {
ast::DefStaticMethod(..) => ck("static method"),
// is whether the trait itself is accessible or not.
method_param(method_param { trait_id: trait_id, .. }) |
method_object(method_object { trait_id: trait_id, .. }) => {
- self.ensure_public(span, trait_id, None, "source trait");
+ self.report_error(self.ensure_public(span, trait_id, None, "source trait"));
}
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
use driver::session::Session;
use metadata::csearch;
use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
pub type LastPrivateMap = HashMap<NodeId, LastPrivate>;
pub enum LastPrivate {
+ LastMod(PrivateDep),
+ // `use` directives (imports) can refer to two separate definitions in the
+ // type and value namespaces. We record here the last private node for each
+ // and whether the import is in fact used for each.
+ // If the Option<PrivateDep> fields are None, it means there is no defintion
+ // in that namespace.
+ LastImport{value_priv: Option<PrivateDep>,
+ value_used: ImportUse,
+ type_priv: Option<PrivateDep>,
+ type_used: ImportUse},
+}
+
+pub enum PrivateDep {
AllPublic,
DependsOn(DefId),
}
+// How an import is used.
+#[deriving(Eq)]
+pub enum ImportUse {
+ Unused, // The import is not used.
+ Used, // The import is used.
+}
+
impl LastPrivate {
fn or(self, other: LastPrivate) -> LastPrivate {
match (self, other) {
- (me, AllPublic) => me,
+ (me, LastMod(AllPublic)) => me,
(_, other) => other,
}
}
ArgumentIrrefutableMode,
}
-#[deriving(Eq)]
+#[deriving(Eq, IterBytes)]
enum Namespace {
TypeNS,
ValueNS
// so as to avoid printing duplicate errors
emit_errors: bool,
- used_imports: HashSet<NodeId>,
+ used_imports: HashSet<(NodeId, Namespace)>,
}
struct BuildReducedGraphVisitor<'a> {
}
-struct UnusedImportCheckVisitor<'a> { resolver: &'a Resolver }
+struct UnusedImportCheckVisitor<'a> { resolver: &'a mut Resolver }
impl<'a> Visitor<()> for UnusedImportCheckVisitor<'a> {
fn visit_view_item(&mut self, vi: &ViewItem, _: ()) {
// First, resolve the module path for the directive, if necessary.
let container = if module_path.len() == 0 {
// Use the crate root.
- Some((self.graph_root.get_module(), AllPublic))
+ Some((self.graph_root.get_module(), LastMod(AllPublic)))
} else {
match self.resolve_module_path(module_,
*module_path,
directive.id,
lp);
+ let lp = match lp {
+ LastMod(lp) => lp,
+ LastImport{..} => self.session.span_bug(directive.span,
+ "Not expecting Import here, must be LastMod"),
+ };
+
// We need to resolve both namespaces for this to succeed.
//
// Unless we managed to find a result in both namespaces (unlikely),
// search imports as well.
- let mut used_reexport = false;
+ let mut value_used_reexport = false;
+ let mut type_used_reexport = false;
match (value_result, type_result) {
(BoundResult(..), BoundResult(..)) => {} // Continue.
_ => {
}
Some(target) => {
let id = import_resolution.id(namespace);
- this.used_imports.insert(id);
+ this.used_imports.insert((id, namespace));
return BoundResult(target.target_module,
target.bindings);
}
if value_result.is_unknown() {
value_result = get_binding(self, *import_resolution,
ValueNS);
- used_reexport = import_resolution.is_public.get();
+ value_used_reexport = import_resolution.is_public.get();
}
if type_result.is_unknown() {
type_result = get_binding(self, *import_resolution,
TypeNS);
- used_reexport = import_resolution.is_public.get();
+ type_used_reexport = import_resolution.is_public.get();
}
}
// If we didn't find a result in the type namespace, search the
// external modules.
- let mut used_public = false;
+ let mut value_used_public = false;
+ let mut type_used_public = false;
match type_result {
BoundResult(..) => {}
_ => {
module);
type_result = BoundResult(containing_module,
name_bindings);
- used_public = true;
+ type_used_public = true;
}
}
}
import_resolution.value_target.set(
Some(Target::new(target_module, name_bindings)));
import_resolution.value_id.set(directive.id);
- used_public = name_bindings.defined_in_public_namespace(ValueNS);
+ value_used_public = name_bindings.defined_in_public_namespace(ValueNS);
}
UnboundResult => { /* Continue. */ }
UnknownResult => {
import_resolution.type_target.set(
Some(Target::new(target_module, name_bindings)));
import_resolution.type_id.set(directive.id);
- used_public = name_bindings.defined_in_public_namespace(TypeNS);
+ type_used_public = name_bindings.defined_in_public_namespace(TypeNS);
}
UnboundResult => { /* Continue. */ }
UnknownResult => {
self.resolve_error(directive.span, msg);
return Failed;
}
- let used_public = used_reexport || used_public;
+ let value_used_public = value_used_reexport || value_used_public;
+ let type_used_public = type_used_reexport || type_used_public;
assert!(import_resolution.outstanding_references.get() >= 1);
import_resolution.outstanding_references.set(
// record what this import resolves to for later uses in documentation,
// this may resolve to either a value or a type, but for documentation
// purposes it's good enough to just favor one over the other.
- match import_resolution.value_target.get() {
+ let value_private = match import_resolution.value_target.get() {
Some(target) => {
let def = target.bindings.def_for_namespace(ValueNS).unwrap();
let mut def_map = self.def_map.borrow_mut();
def_map.get().insert(directive.id, def);
let did = def_id_of_def(def);
- self.last_private.insert(directive.id,
- if used_public {lp} else {DependsOn(did)});
- }
- None => {}
- }
- match import_resolution.type_target.get() {
+ if value_used_public {Some(lp)} else {Some(DependsOn(did))}
+ },
+ // AllPublic here and below is a dummy value, it should never be used because
+ // _exists is false.
+ None => None,
+ };
+ let type_private = match import_resolution.type_target.get() {
Some(target) => {
let def = target.bindings.def_for_namespace(TypeNS).unwrap();
let mut def_map = self.def_map.borrow_mut();
def_map.get().insert(directive.id, def);
let did = def_id_of_def(def);
- self.last_private.insert(directive.id,
- if used_public {lp} else {DependsOn(did)});
- }
- None => {}
- }
+ if type_used_public {Some(lp)} else {Some(DependsOn(did))}
+ },
+ None => None,
+ };
+
+ self.last_private.insert(directive.id, LastImport{value_priv: value_private,
+ value_used: Used,
+ type_priv: type_private,
+ type_used: Used});
debug!("(resolving single import) successfully resolved import");
return Success(());
.get() {
Some(did) => {
closest_private =
- DependsOn(did);
+ LastMod(DependsOn(did));
}
None => {}
}
// resolution process at index zero.
search_module = self.graph_root.get_module();
start_index = 0;
- last_private = AllPublic;
+ last_private = LastMod(AllPublic);
}
UseLexicalScope => {
// This is not a crate-relative path. We resolve the
Success(containing_module) => {
search_module = containing_module;
start_index = 1;
- last_private = AllPublic;
+ last_private = LastMod(AllPublic);
}
}
}
Success(PrefixFound(containing_module, index)) => {
search_module = containing_module;
start_index = index;
- last_private = DependsOn(containing_module.def_id
- .get()
- .unwrap());
+ last_private = LastMod(DependsOn(containing_module.def_id
+ .get()
+ .unwrap()));
}
}
Some(target) => {
debug!("(resolving item in lexical scope) using \
import resolution");
- self.used_imports.insert(import_resolution.id(namespace));
+ self.used_imports.insert((import_resolution.id(namespace), namespace));
return Success((target, false));
}
}
Some(target) => {
debug!("(resolving name in module) resolved to \
import");
- self.used_imports.insert(import_resolution.id(namespace));
+ self.used_imports.insert((import_resolution.id(namespace), namespace));
return Success((target, true));
}
}
// Associate this type parameter with
// the item that bound it
self.record_def(type_parameter.id,
- (DefTyParamBinder(node_id), AllPublic));
+ (DefTyParamBinder(node_id), LastMod(AllPublic)));
// plain insert (no renaming)
let mut bindings = function_type_rib.bindings
.borrow_mut();
Some(&primitive_type) => {
result_def =
- Some((DefPrimTy(primitive_type), AllPublic));
+ Some((DefPrimTy(primitive_type), LastMod(AllPublic)));
if path.segments
.iter()
// will be able to distinguish variants from
// locals in patterns.
- self.record_def(pattern.id, (def, AllPublic));
+ self.record_def(pattern.id, (def, LastMod(AllPublic)));
// Add the binding to the local ribs, if it
// doesn't already exist in the bindings list. (We
// the lookup happened only within the current module.
match def.def {
def @ DefVariant(..) | def @ DefStruct(..) => {
- return FoundStructOrEnumVariant(def, AllPublic);
+ return FoundStructOrEnumVariant(def, LastMod(AllPublic));
}
def @ DefStatic(_, false) => {
- return FoundConst(def, AllPublic);
+ return FoundConst(def, LastMod(AllPublic));
}
_ => {
return BareIdentifierPatternUnresolved;
namespace,
span) {
Some(def) => {
- return Some((def, AllPublic));
+ return Some((def, LastMod(AllPublic)));
}
None => {
// Continue.
// Found it. Stop the search here.
let p = child_name_bindings.defined_in_public_namespace(
namespace);
- let lp = if p {AllPublic} else {
- DependsOn(def_id_of_def(def))
+ let lp = if p {LastMod(AllPublic)} else {
+ LastMod(DependsOn(def_id_of_def(def)))
};
return ChildNameDefinition(def, lp);
}
Some(def) => {
// Found it.
let id = import_resolution.id(namespace);
- self.used_imports.insert(id);
- return ImportNameDefinition(def, AllPublic);
+ self.used_imports.insert((id, namespace));
+ return ImportNameDefinition(def, LastMod(AllPublic));
}
None => {
// This can happen with external impls, due to
match module.def_id.get() {
None => {} // Continue.
Some(def_id) => {
- let lp = if module.is_public {AllPublic} else {
- DependsOn(def_id)
+ let lp = if module.is_public {LastMod(AllPublic)} else {
+ LastMod(DependsOn(def_id))
};
return ChildNameDefinition(DefMod(def_id), lp);
}
0,
path.span,
PathSearch,
- AllPublic) {
+ LastMod(AllPublic)) {
Failed => {
let msg = format!("use of undeclared module `::{}`",
self.idents_to_str(module_path_idents));
// This lookup is "all public" because it only searched
// for one identifier in the current module (couldn't
// have passed through reexports or anything like that.
- return Some((def, AllPublic));
+ return Some((def, LastMod(AllPublic)));
}
}
}
format!("use of undeclared label `{}`",
token::get_name(label))),
Some(DlDef(def @ DefLabel(_))) => {
- // FIXME: is AllPublic correct?
- self.record_def(expr.id, (def, AllPublic))
+ // Since this def is a label, it is never read.
+ self.record_def(expr.id, (def, LastMod(AllPublic)))
}
Some(_) => {
self.session.span_bug(expr.span,
};
if candidate_traits.contains(&did) {
self.add_trait_info(&mut found_traits, did, name);
- self.used_imports.insert(import.type_id.get());
+ self.used_imports.insert((import.type_id.get(), TypeNS));
}
}
fn record_def(&mut self, node_id: NodeId, (def, lp): (Def, LastPrivate)) {
debug!("(recording def) recording {:?} for {:?}, last private {:?}",
def, node_id, lp);
+ assert!(match lp {LastImport{..} => false, _ => true},
+ "Import should only be used for `use` directives");
self.last_private.insert(node_id, lp);
let mut def_map = self.def_map.borrow_mut();
def_map.get().insert_or_update_with(node_id, def, |_, old_value| {
//
// Unused import checking
//
- // Although this is a lint pass, it lives in here because it depends on
- // resolve data structures.
+ // Although this is mostly a lint pass, it lives in here because it depends on
+ // resolve data structures and because it finalises the privacy information for
+ // `use` directives.
//
- fn check_for_unused_imports(&self, krate: &ast::Crate) {
+ fn check_for_unused_imports(&mut self, krate: &ast::Crate) {
let mut visitor = UnusedImportCheckVisitor{ resolver: self };
visit::walk_crate(&mut visitor, krate, ());
}
- fn check_for_item_unused_imports(&self, vi: &ViewItem) {
+ fn check_for_item_unused_imports(&mut self, vi: &ViewItem) {
// Ignore is_public import statements because there's no way to be sure
// whether they're used or not. Also ignore imports with a dummy span
// because this means that they were generated in some fashion by the
ViewItemUse(ref path) => {
for p in path.iter() {
match p.node {
- ViewPathSimple(_, _, id) | ViewPathGlob(_, id) => {
- if !self.used_imports.contains(&id) {
- self.session.add_lint(UnusedImports,
- id, p.span,
- ~"unused import");
- }
- }
-
+ ViewPathSimple(_, _, id) => self.finalize_import(id, p.span),
ViewPathList(_, ref list, _) => {
for i in list.iter() {
- if !self.used_imports.contains(&i.node.id) {
- self.session.add_lint(UnusedImports,
- i.node.id, i.span,
- ~"unused import");
- }
+ self.finalize_import(i.node.id, i.span);
}
- }
+ },
+ ViewPathGlob(_, id) => {
+ if !self.used_imports.contains(&(id, TypeNS)) &&
+ !self.used_imports.contains(&(id, ValueNS)) {
+ self.session.add_lint(UnusedImports, id, p.span, ~"unused import");
+ }
+ },
}
}
}
}
}
+ // We have information about whether `use` (import) directives are actually used now.
+ // If an import is not used at all, we signal a lint error. If an import is only used
+ // for a single namespace, we remove the other namespace from the recorded privacy
+ // information. That means in privacy.rs, we will only check imports and namespaces
+ // which are used. In particular, this means that if an import could name either a
+ // public or private item, we will check the correct thing, dependent on how the import
+ // is used.
+ fn finalize_import(&mut self, id: NodeId, span: Span) {
+ debug!("finalizing import uses for {}", self.session.codemap.span_to_snippet(span));
+
+ if !self.used_imports.contains(&(id, TypeNS)) &&
+ !self.used_imports.contains(&(id, ValueNS)) {
+ self.session.add_lint(UnusedImports, id, span, ~"unused import");
+ }
+
+ let (v_priv, t_priv) = match self.last_private.find(&id) {
+ Some(&LastImport{value_priv: v,
+ value_used: _,
+ type_priv: t,
+ type_used: _}) => (v, t),
+ Some(_) => fail!("We should only have LastImport for `use` directives"),
+ _ => return,
+ };
+
+ let mut v_used = if self.used_imports.contains(&(id, ValueNS)) {
+ Used
+ } else {
+ Unused
+ };
+ let t_used = if self.used_imports.contains(&(id, TypeNS)) {
+ Used
+ } else {
+ Unused
+ };
+
+ match (v_priv, t_priv) {
+ // Since some items may be both in the value _and_ type namespaces (e.g., structs)
+ // we might have two LastPrivates pointing at the same thing. There is no point
+ // checking both, so lets not check the value one.
+ (Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused,
+ _ => {},
+ }
+
+ self.last_private.insert(id, LastImport{value_priv: v_priv,
+ value_used: v_used,
+ type_priv: t_priv,
+ type_used: t_used});
+ }
+
//
// Diagnostics
//
.span_err(e.span,
format!("expected \
constant: {}",
- (*err)));
+ *err));
}
},
None => {}
e, actual)})},
Some(expected),
format!("{} pattern", match pointer_kind {
- Send => "a ~-box",
- Borrowed => "an &-pointer"
+ Send => "a `~`-box",
+ Borrowed => "an `&`-pointer"
}),
None);
fcx.write_error(pat_id);
self.tcx().sess.span_note(
span,
format!("candidate \\#{} is `{}`",
- (idx+1u),
+ idx+1u,
ty::item_path_str(self.tcx(), did)));
}
self.tcx().sess.span_note(
self.expr.span,
format!("candidate \\#{} derives from the bound `{}`",
- (idx+1u),
+ idx+1u,
ty::item_path_str(self.tcx(), did)));
}
self.expr.span,
format!("candidate \\#{} derives from the type of the receiver, \
which is the trait `{}`",
- (idx+1u),
+ idx+1u,
ty::item_path_str(self.tcx(), did)));
}
ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
}
Err(ref err) => {
- ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", (*err)));
+ ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
}
}
},
(ref str, Some(span)) => {
cx.sess.span_note(
span,
- format!("{}{}{}", prefix, (*str), suffix));
+ format!("{}{}{}", prefix, *str, suffix));
}
(ref str, None) => {
cx.sess.note(
- format!("{}{}{}", prefix, (*str), suffix));
+ format!("{}{}{}", prefix, *str, suffix));
}
}
}
use rustc::metadata::decoder;
use std;
-use std::hashmap::HashMap;
use doctree;
use visit_ast;
pub struct Crate {
name: ~str,
module: Option<Item>,
- externs: HashMap<ast::CrateNum, ExternalCrate>,
+ externs: ~[(ast::CrateNum, ExternalCrate)],
}
impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
use syntax::attr::find_crateid;
let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
- let mut externs = HashMap::new();
+ let mut externs = ~[];
cx.sess.cstore.iter_crate_data(|n, meta| {
- externs.insert(n, meta.clean());
+ externs.push((n, meta.clean()));
});
Crate {
VariantItem(Variant),
ForeignFunctionItem(Function),
ForeignStaticItem(Static),
+ MacroItem(Macro),
}
#[deriving(Clone, Encodable, Decodable)]
self.fns.clean(), self.foreigns.clean().concat_vec(),
self.mods.clean(), self.typedefs.clean(),
self.statics.clean(), self.traits.clean(),
- self.impls.clean(), self.view_items.clean()].concat_vec()
+ self.impls.clean(), self.view_items.clean(),
+ self.macros.clean()].concat_vec()
})
}
}
None => None
}
}
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Macro {
+ source: ~str,
+}
+
+impl Clean<Item> for doctree::Macro {
+ fn clean(&self) -> Item {
+ Item {
+ name: Some(self.name.clean()),
+ attrs: self.attrs.clean(),
+ source: self.where.clean(),
+ visibility: ast::Public.clean(),
+ id: self.id,
+ inner: MacroItem(Macro {
+ source: self.where.to_src(),
+ }),
+ }
+ }
+}
impls: ~[Impl],
foreigns: ~[ast::ForeignMod],
view_items: ~[ast::ViewItem],
+ macros: ~[Macro],
}
impl Module {
impls : ~[],
view_items : ~[],
foreigns : ~[],
+ macros : ~[],
}
}
}
id: ast::NodeId,
}
+pub struct Macro {
+ name: Ident,
+ id: ast::NodeId,
+ attrs: ~[ast::Attribute],
+ where: Span,
+}
+
pub fn struct_type_from_def(sd: &ast::StructDef) -> StructType {
if sd.ctor_id.is_some() {
// We are in a tuple-struct
priv parent_stack: ~[ast::NodeId],
priv search_index: ~[IndexItem],
priv privmod: bool,
+ priv public_items: HashSet<ast::NodeId>,
}
/// Helper struct to render all source code to HTML pages
}
// 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: ~[],
- extern_locations: HashMap::new(),
- privmod: false,
- };
+ let mut cache = local_data::get(::analysiskey, |analysis| {
+ let public_items = analysis.map(|a| a.public_items.clone());
+ let public_items = public_items.unwrap_or(HashSet::new());
+ Cache {
+ impls: HashMap::new(),
+ typarams: HashMap::new(),
+ paths: HashMap::new(),
+ traits: HashMap::new(),
+ implementors: HashMap::new(),
+ stack: ~[],
+ parent_stack: ~[],
+ search_index: ~[],
+ extern_locations: HashMap::new(),
+ privmod: false,
+ public_items: public_items,
+ }
+ });
cache.stack.push(krate.name.clone());
krate = cache.fold_crate(krate);
krate = folder.fold_crate(krate);
}
- for (&n, e) in krate.externs.iter() {
+ for &(n, ref e) in krate.externs.iter() {
cache.extern_locations.insert(n, extern_location(e, &cx.dst));
}
clean::StructItem(..) | clean::EnumItem(..) |
clean::TypedefItem(..) | clean::TraitItem(..) |
clean::FunctionItem(..) | clean::ModuleItem(..) |
- clean::ForeignFunctionItem(..) | clean::VariantItem(..) => {
- self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
+ clean::ForeignFunctionItem(..) => {
+ // Reexported items mean that the same id can show up twice in
+ // the rustdoc ast that we're looking at. We know, however, that
+ // a reexported item doesn't show up in the `public_items` map,
+ // so we can skip inserting into the paths map if there was
+ // already an entry present and we're not a public item.
+ if !self.paths.contains_key(&item.id) ||
+ self.public_items.contains(&item.id) {
+ self.paths.insert(item.id,
+ (self.stack.clone(), shortty(&item)));
+ }
+ }
+ // link variants to their parent enum because pages aren't emitted
+ // for each variant
+ clean::VariantItem(..) => {
+ let mut stack = self.stack.clone();
+ stack.pop();
+ self.paths.insert(item.id, (stack, "enum"));
}
_ => {}
}
clean::VariantItem(..) => "variant",
clean::ForeignFunctionItem(..) => "ffi",
clean::ForeignStaticItem(..) => "ffs",
+ clean::MacroItem(..) => "macro",
}
}
clean::StructItem(ref s) => item_struct(fmt.buf, self.item, s),
clean::EnumItem(ref e) => item_enum(fmt.buf, self.item, e),
clean::TypedefItem(ref t) => item_typedef(fmt.buf, self.item, t),
+ clean::MacroItem(ref m) => item_macro(fmt.buf, self.item, m),
_ => Ok(())
}
}
(_, &clean::ViewItemItem(..)) => Greater,
(&clean::ModuleItem(..), _) => Less,
(_, &clean::ModuleItem(..)) => Greater,
+ (&clean::MacroItem(..), _) => Less,
+ (_, &clean::MacroItem(..)) => Greater,
(&clean::StructItem(..), _) => Less,
(_, &clean::StructItem(..)) => Greater,
(&clean::EnumItem(..), _) => Less,
clean::VariantItem(..) => "Variants",
clean::ForeignFunctionItem(..) => "Foreign Functions",
clean::ForeignStaticItem(..) => "Foreign Statics",
+ clean::MacroItem(..) => "Macros",
}));
}
if_ok!(write!(w, "\\{\n"));
for m in required.iter() {
if_ok!(write!(w, " "));
- if_ok!(render_method(w, m.item(), true));
+ if_ok!(render_method(w, m.item()));
if_ok!(write!(w, ";\n"));
}
if required.len() > 0 && provided.len() > 0 {
}
for m in provided.iter() {
if_ok!(write!(w, " "));
- if_ok!(render_method(w, m.item(), true));
+ if_ok!(render_method(w, m.item()));
if_ok!(write!(w, " \\{ ... \\}\n"));
}
if_ok!(write!(w, "\\}"));
if_ok!(write!(w, "<h3 id='{}.{}' class='method'><code>",
shortty(m.item()),
*m.item().name.get_ref()));
- if_ok!(render_method(w, m.item(), false));
+ if_ok!(render_method(w, m.item()));
if_ok!(write!(w, "</code></h3>"));
if_ok!(document(w, m.item()));
Ok(())
})
}
-fn render_method(w: &mut Writer, meth: &clean::Item,
- withlink: bool) -> fmt::Result {
+fn render_method(w: &mut Writer, meth: &clean::Item) -> fmt::Result {
fn fun(w: &mut Writer, it: &clean::Item, purity: ast::Purity,
- g: &clean::Generics, selfty: &clean::SelfTy, d: &clean::FnDecl,
- withlink: bool) -> fmt::Result {
- write!(w, "{}fn {withlink, select,
- true{<a href='\\#{ty}.{name}'
- class='fnname'>{name}</a>}
- other{<span class='fnname'>{name}</span>}
- }{generics}{decl}",
+ g: &clean::Generics, selfty: &clean::SelfTy,
+ d: &clean::FnDecl) -> fmt::Result {
+ write!(w, "{}fn <a href='\\#{ty}.{name}' class='fnname'>{name}</a>\
+ {generics}{decl}",
match purity {
ast::UnsafeFn => "unsafe ",
_ => "",
ty = shortty(it),
name = it.name.get_ref().as_slice(),
generics = *g,
- decl = Method(selfty, d),
- withlink = if withlink {"true"} else {"false"})
+ decl = Method(selfty, d))
}
match meth.inner {
clean::TyMethodItem(ref m) => {
- fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink)
+ fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl)
}
clean::MethodItem(ref m) => {
- fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink)
+ fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl)
}
_ => unreachable!()
}
fn docmeth(w: &mut Writer, item: &clean::Item) -> io::IoResult<bool> {
if_ok!(write!(w, "<h4 id='method.{}' class='method'><code>",
*item.name.get_ref()));
- if_ok!(render_method(w, item, false));
+ if_ok!(render_method(w, item));
if_ok!(write!(w, "</code></h4>\n"));
match item.doc_value() {
Some(s) => {
Ok(())
}
}
+
+fn item_macro(w: &mut Writer, it: &clean::Item,
+ t: &clean::Macro) -> fmt::Result {
+ if_ok!(write!(w, "<pre class='macro'>{}</pre>", t.source));
+ document(w, it)
+}
.stability.Stable { border-color: #AEC516; color: #7c8b10; }
.stability.Frozen { border-color: #009431; color: #007726; }
.stability.Locked { border-color: #0084B6; color: #00668c; }
+
+:target { background: #FDFFD3; }
};
let crate_json = match json::from_str(crate_json_str) {
Ok(j) => j,
- Err(_) => fail!("Rust generated JSON is invalid??")
+ Err(e) => fail!("Rust generated JSON is invalid: {:?}", e)
};
json.insert(~"crate", crate_json);
}
clean::ImplItem(..) => {}
- // tymethods have no control over privacy
- clean::TyMethodItem(..) => {}
+ // tymethods/macros have no control over privacy
+ clean::MacroItem(..) | clean::TyMethodItem(..) => {}
}
let fastreturn = match i.inner {
#[deny(warnings)];
#[allow(unused_variable, dead_assignment, unused_mut, attribute_usage, dead_code)];
";
- if s.contains("extra") {
- prog.push_str("extern crate extra;\n");
- }
- if s.contains(cratename) {
- prog.push_str(format!("extern crate {};\n", cratename));
+ if !s.contains("extern crate") {
+ if s.contains("extra") {
+ prog.push_str("extern crate extra;\n");
+ }
+ if s.contains(cratename) {
+ prog.push_str(format!("extern crate {};\n", cratename));
+ }
}
if s.contains("fn main") {
prog.push_str(s);
ast::ItemForeignMod(ref fm) => {
om.foreigns.push(fm.clone());
}
- _ => (),
+ ast::ItemMac(ref _m) => {
+ om.macros.push(Macro {
+ id: item.id,
+ attrs: item.attrs.clone(),
+ name: item.ident,
+ where: item.span,
+ })
+ }
}
}
}
#[test] #[should_fail]
fn smoke_fail() {
+ // By default, the test harness is capturing our stderr output through a
+ // channel. This means that when we start failing and "print" our error
+ // message, we could be switched to running on another test. The
+ // IdleWatcher assumes that we're already running on the same task, so
+ // it can cause serious problems and internal race conditions.
+ //
+ // To fix this bug, we just set our stderr to a null writer which will
+ // never reschedule us, so we're guaranteed to stay on the same
+ // task/event loop.
+ use std::io;
+ drop(io::stdio::set_stderr(~io::util::NullWriter));
+
let (mut idle, _chan) = mk(1);
idle.resume();
fail!();
#[cfg(test)]
mod test {
use std::cast::transmute;
- use std::ptr;
use std::unstable::run_in_bare_thread;
use super::{slice_to_uv_buf, Loop};
}
}
- /// Waits for an event on this port set. The returned valus is *not* and
+ /// Waits for an event on this port set. The returned value is *not* an
/// index, but rather an id. This id can be queried against any active
/// `Handle` structures (each one has an `id` method). The handle with
/// the matching `id` will have some sort of event available on it. The
///
/// Since connection attempts can continue forever, this iterator always returns
/// `Some`. The `Some` contains the `IoResult` representing whether the
-/// connection attempt was succesful. A successful connection will be wrapped
+/// connection attempt was successful. A successful connection will be wrapped
/// in `Ok`. A failed connection is represented as an `Err`.
pub struct IncomingConnections<'a, A> {
priv inc: &'a mut A,
pub mod tcp;
pub mod udp;
pub mod ip;
-#[cfg(unix)]
+// FIXME(#12093) - this should not be called unix
pub mod unix;
use io::*;
use io::test::*;
- fn smalltest(server: proc(UnixStream), client: proc(UnixStream)) {
+ pub fn smalltest(server: proc(UnixStream), client: proc(UnixStream)) {
let path1 = next_test_unix();
let path2 = path1.clone();
let (port, chan) = Chan::new();
server(acceptor.accept().unwrap());
}
- #[test]
- fn bind_error() {
- match UnixListener::bind(&("path/to/nowhere")) {
+ iotest!(fn bind_error() {
+ let path = "path/to/nowhere";
+ match UnixListener::bind(&path) {
Ok(..) => fail!(),
- Err(e) => assert_eq!(e.kind, PermissionDenied),
+ Err(e) => {
+ assert!(e.kind == PermissionDenied || e.kind == FileNotFound ||
+ e.kind == InvalidInput);
+ }
}
- }
-
- #[test]
- fn connect_error() {
- match UnixStream::connect(&("path/to/nowhere")) {
+ })
+
+ iotest!(fn connect_error() {
+ let path = if cfg!(windows) {
+ r"\\.\pipe\this_should_not_exist_ever"
+ } else {
+ "path/to/nowhere"
+ };
+ match UnixStream::connect(&path) {
Ok(..) => fail!(),
- Err(e) => assert_eq!(e.kind,
- if cfg!(windows) {OtherIoError} else {FileNotFound})
+ Err(e) => {
+ assert!(e.kind == FileNotFound || e.kind == OtherIoError);
+ }
}
- }
+ })
- #[test]
- fn smoke() {
+ iotest!(fn smoke() {
smalltest(proc(mut server) {
let mut buf = [0];
server.read(buf).unwrap();
}, proc(mut client) {
client.write([99]).unwrap();
})
- }
+ })
- #[test]
- fn read_eof() {
+ iotest!(fn read_eof() {
smalltest(proc(mut server) {
let mut buf = [0];
assert!(server.read(buf).is_err());
}, proc(_client) {
// drop the client
})
- }
+ })
- #[test]
- fn write_begone() {
+ iotest!(fn write_begone() {
smalltest(proc(mut server) {
let buf = [0];
loop {
match server.write(buf) {
Ok(..) => {}
Err(e) => {
- assert!(e.kind == BrokenPipe || e.kind == NotConnected,
+ assert!(e.kind == BrokenPipe ||
+ e.kind == NotConnected ||
+ e.kind == ConnectionReset,
"unknown error {:?}", e);
break;
}
}, proc(_client) {
// drop the client
})
- }
+ })
- #[test]
- fn accept_lots() {
+ iotest!(fn accept_lots() {
let times = 10;
let path1 = next_test_unix();
let path2 = path1.clone();
port.recv();
for _ in range(0, times) {
let mut stream = UnixStream::connect(&path2);
- stream.write([100]).unwrap();
+ match stream.write([100]) {
+ Ok(..) => {}
+ Err(e) => fail!("failed write: {}", e)
+ }
}
});
- let mut acceptor = UnixListener::bind(&path1).listen();
+ let mut acceptor = match UnixListener::bind(&path1).listen() {
+ Ok(a) => a,
+ Err(e) => fail!("failed listen: {}", e),
+ };
chan.send(());
for _ in range(0, times) {
let mut client = acceptor.accept();
let mut buf = [0];
- client.read(buf).unwrap();
+ match client.read(buf) {
+ Ok(..) => {}
+ Err(e) => fail!("failed read/accept: {}", e),
+ }
assert_eq!(buf[0], 100);
}
- }
+ })
- #[test]
- fn path_exists() {
+ #[cfg(unix)]
+ iotest!(fn path_exists() {
let path = next_test_unix();
let _acceptor = UnixListener::bind(&path).listen();
assert!(path.exists());
- }
+ })
- #[test]
- fn unix_clone_smoke() {
+ iotest!(fn unix_clone_smoke() {
let addr = next_test_unix();
let mut acceptor = UnixListener::bind(&addr).listen();
spawn(proc() {
let mut s = UnixStream::connect(&addr);
let mut buf = [0, 0];
+ debug!("client reading");
assert_eq!(s.read(buf), Ok(1));
assert_eq!(buf[0], 1);
+ debug!("client writing");
s.write([2]).unwrap();
+ debug!("client dropping");
});
let mut s1 = acceptor.accept().unwrap();
spawn(proc() {
let mut s2 = s2;
p1.recv();
+ debug!("writer writing");
s2.write([1]).unwrap();
+ debug!("writer done");
c2.send(());
});
c1.send(());
let mut buf = [0, 0];
+ debug!("reader reading");
assert_eq!(s1.read(buf), Ok(1));
+ debug!("reader done");
p2.recv();
- }
+ })
- #[test]
- fn unix_clone_two_read() {
+ iotest!(fn unix_clone_two_read() {
let addr = next_test_unix();
let mut acceptor = UnixListener::bind(&addr).listen();
let (p, c) = Chan::new();
c.send(());
p.recv();
- }
+ })
- #[test]
- fn unix_clone_two_write() {
+ iotest!(fn unix_clone_two_write() {
let addr = next_test_unix();
let mut acceptor = UnixListener::bind(&addr).listen();
s1.write([2]).unwrap();
p.recv();
- }
+ })
}
/// ```
fn min(&mut self) -> Option<A>;
- /// `min_max` finds the mininum and maximum elements in the iterator.
+ /// `min_max` finds the minimum and maximum elements in the iterator.
///
/// The return type `MinMaxResult` is an enum of three variants:
/// - `NoElements` if the iterator is empty.
#[cfg(test)] pub use ops = realstd::ops;
#[cfg(test)] pub use cmp = realstd::cmp;
-mod macros;
+pub mod macros;
mod rtdeps;
ai_canonname: *c_char,
ai_next: *addrinfo
}
+ pub struct sockaddr_un {
+ sun_family: sa_family_t,
+ sun_path: [c_char, ..108]
+ }
}
}
ai_addr: *sockaddr,
ai_next: *addrinfo
}
+ pub struct sockaddr_un {
+ sun_len: u8,
+ sun_family: sa_family_t,
+ sun_path: [c_char, ..104]
+ }
}
}
ai_addr: *sockaddr,
ai_next: *addrinfo
}
+ pub struct sockaddr_un {
+ sun_family: sa_family_t,
+ sun_path: [c_char, ..108]
+ }
}
}
ai_addr: *sockaddr,
ai_next: *addrinfo
}
+ pub struct sockaddr_un {
+ sun_len: u8,
+ sun_family: sa_family_t,
+ sun_path: [c_char, ..104]
+ }
}
}
pub static O_NOINHERIT: c_int = 128;
pub static ERROR_SUCCESS : c_int = 0;
+ pub static ERROR_FILE_NOT_FOUND: c_int = 2;
+ pub static ERROR_ACCESS_DENIED: c_int = 5;
pub static ERROR_INVALID_HANDLE : c_int = 6;
+ pub static ERROR_BROKEN_PIPE: c_int = 109;
pub static ERROR_DISK_FULL : c_int = 112;
pub static ERROR_INSUFFICIENT_BUFFER : c_int = 122;
+ pub static ERROR_INVALID_NAME : c_int = 123;
pub static ERROR_ALREADY_EXISTS : c_int = 183;
+ pub static ERROR_PIPE_BUSY: c_int = 231;
+ pub static ERROR_NO_DATA: c_int = 232;
pub static ERROR_INVALID_ADDRESS : c_int = 487;
+ pub static ERROR_PIPE_CONNECTED: c_int = 535;
+ pub static ERROR_IO_PENDING: c_int = 997;
pub static ERROR_FILE_INVALID : c_int = 1006;
pub static INVALID_HANDLE_VALUE : c_int = -1;
pub static FILE_FLAG_SESSION_AWARE: DWORD = 0x00800000;
pub static FILE_FLAG_SEQUENTIAL_SCAN: DWORD = 0x08000000;
pub static FILE_FLAG_WRITE_THROUGH: DWORD = 0x80000000;
+ pub static FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
pub static FILE_NAME_NORMALIZED: DWORD = 0x0;
pub static FILE_NAME_OPENED: DWORD = 0x8;
pub static GENERIC_WRITE: DWORD = 0x40000000;
pub static GENERIC_EXECUTE: DWORD = 0x20000000;
pub static GENERIC_ALL: DWORD = 0x10000000;
+ pub static FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100;
+ pub static FILE_READ_ATTRIBUTES: DWORD = 0x00000080;
pub static FILE_BEGIN: DWORD = 0;
pub static FILE_CURRENT: DWORD = 1;
pub static DETACHED_PROCESS: DWORD = 0x00000008;
pub static CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200;
+
+ pub static PIPE_ACCESS_DUPLEX: DWORD = 0x00000003;
+ pub static PIPE_ACCESS_INBOUND: DWORD = 0x00000001;
+ pub static PIPE_ACCESS_OUTBOUND: DWORD = 0x00000002;
+ pub static PIPE_TYPE_BYTE: DWORD = 0x00000000;
+ pub static PIPE_TYPE_MESSAGE: DWORD = 0x00000004;
+ pub static PIPE_READMODE_BYTE: DWORD = 0x00000000;
+ pub static PIPE_READMODE_MESSAGE: DWORD = 0x00000002;
+ pub static PIPE_WAIT: DWORD = 0x00000000;
+ pub static PIPE_NOWAIT: DWORD = 0x00000001;
+ pub static PIPE_ACCEPT_REMOTE_CLIENTS: DWORD = 0x00000000;
+ pub static PIPE_REJECT_REMOTE_CLIENTS: DWORD = 0x00000008;
+ pub static PIPE_UNLIMITED_INSTANCES: DWORD = 255;
}
pub mod sysconf {
}
pub static MADV_UNMERGEABLE : c_int = 13;
pub static MADV_HWPOISON : c_int = 100;
+ pub static AF_UNIX: c_int = 1;
pub static AF_INET: c_int = 2;
pub static AF_INET6: c_int = 10;
pub static SOCK_STREAM: c_int = 1;
pub static AF_INET: c_int = 2;
pub static AF_INET6: c_int = 28;
+ pub static AF_UNIX: c_int = 1;
pub static SOCK_STREAM: c_int = 1;
pub static SOCK_DGRAM: c_int = 2;
pub static IPPROTO_TCP: c_int = 6;
pub static MINCORE_REFERENCED_OTHER : c_int = 0x8;
pub static MINCORE_MODIFIED_OTHER : c_int = 0x10;
+ pub static AF_UNIX: c_int = 1;
pub static AF_INET: c_int = 2;
pub static AF_INET6: c_int = 30;
pub static SOCK_STREAM: c_int = 1;
lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL;
pub fn GetCurrentProcessId() -> DWORD;
+ pub fn CreateNamedPipeW(
+ lpName: LPCWSTR,
+ dwOpenMode: DWORD,
+ dwPipeMode: DWORD,
+ nMaxInstances: DWORD,
+ nOutBufferSize: DWORD,
+ nInBufferSize: DWORD,
+ nDefaultTimeOut: DWORD,
+ lpSecurityAttributes: LPSECURITY_ATTRIBUTES
+ ) -> HANDLE;
+ pub fn ConnectNamedPipe(hNamedPipe: HANDLE,
+ lpOverlapped: LPOVERLAPPED) -> BOOL;
+ pub fn WaitNamedPipeW(lpNamedPipeName: LPCWSTR,
+ nTimeOut: DWORD) -> BOOL;
+ pub fn SetNamedPipeHandleState(hNamedPipe: HANDLE,
+ lpMode: LPDWORD,
+ lpMaxCollectionCount: LPDWORD,
+ lpCollectDataTimeout: LPDWORD)
+ -> BOOL;
+ pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES,
+ bManualReset: BOOL,
+ bInitialState: BOOL,
+ lpName: LPCWSTR) -> HANDLE;
+ pub fn GetOverlappedResult(hFile: HANDLE,
+ lpOverlapped: LPOVERLAPPED,
+ lpNumberOfBytesTransferred: LPDWORD,
+ bWait: BOOL) -> BOOL;
+ pub fn DisconnectNamedPipe(hNamedPipe: HANDLE) -> BOOL;
}
}
// <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.
+
+//! Standard library macros
+//!
+//! This modules contains a set of macros which are exported from the standard
+//! library. Each macro is available for use when linking against the standard
+//! library.
+
#[macro_escape];
+/// The standard logging macro
+///
+/// This macro will generically log over a provided level (of type u32) with a
+/// format!-based argument list. See documentation in `std::fmt` for details on
+/// how to use the syntax, and documentation in `std::logging` for info about
+/// logging macros.
+///
+/// # Example
+///
+/// ```
+/// log!(::std::logging::DEBUG, "this is a debug message");
+/// log!(::std::logging::WARN, "this is a warning {}", "message");
+/// log!(6, "this is a custom logging level: {level}", level=6);
+/// ```
#[macro_export]
macro_rules! log(
($lvl:expr, $($arg:tt)+) => ({
})
)
+/// A convenience macro for logging at the error log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let error = 3;
+/// error!("the build has failed with error code: {}", error);
+/// ```
#[macro_export]
macro_rules! error(
($($arg:tt)*) => (log!(1u32, $($arg)*))
)
+/// A convenience macro for logging at the warning log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let code = 3;
+/// warn!("you may like to know that a process exited with: {}", code);
+/// ```
#[macro_export]
macro_rules! warn(
($($arg:tt)*) => (log!(2u32, $($arg)*))
)
+/// A convenience macro for logging at the info log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let ret = 3;
+/// info!("this function is about to return: {}", ret);
+/// ```
#[macro_export]
macro_rules! info(
($($arg:tt)*) => (log!(3u32, $($arg)*))
)
+/// A convenience macro for logging at the debug log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// debug!("x = {x}, y = {y}", x=10, y=20);
+/// ```
#[macro_export]
macro_rules! debug(
($($arg:tt)*) => (if cfg!(not(ndebug)) { log!(4u32, $($arg)*) })
)
+/// A macro to test whether a log level is enabled for the current module.
+///
+/// # Example
+///
+/// ```
+/// # struct Point { x: int, y: int }
+/// # fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } }
+/// if log_enabled!(std::logging::DEBUG) {
+/// let x = some_expensive_computation();
+/// debug!("x.x = {}, x.y = {}", x.x, x.y);
+/// }
+/// ```
#[macro_export]
macro_rules! log_enabled(
($lvl:expr) => ({
})
)
+/// The entry point for failure of rust tasks.
+///
+/// This macro is used to inject failure into a rust task, causing the task to
+/// unwind and fail entirely. Each task's failure can be reaped as the `~Any`
+/// type, and the single-argument form of the `fail!` macro will be the value
+/// which is transmitted.
+///
+/// The multi-argument form of this macro fails with a string and has the
+/// `format!` sytnax for building a string.
+///
+/// # Example
+///
+/// ```should_fail
+/// # #[allow(unreachable_code)];
+/// fail!();
+/// fail!("this is a terrible mistake!");
+/// fail!(4); // fail with the value of 4 to be collected elsewhere
+/// fail!("this is a {} {message}", "fancy", message = "message");
+/// ```
#[macro_export]
macro_rules! fail(
() => (
});
)
+/// Ensure that a boolean expression is `true` at runtime.
+///
+/// This will invoke the `fail!` macro if the provided expression cannot be
+/// evaluated to `true` at runtime.
+///
+/// # Example
+///
+/// ```
+/// // the failure message for these assertions is the stringified value of the
+/// // expression given.
+/// assert!(true);
+/// # fn some_computation() -> bool { true }
+/// assert!(some_computation());
+///
+/// // assert with a custom message
+/// # let x = true;
+/// assert!(x, "x wasn't true!");
+/// # let a = 3; let b = 27;
+/// assert!(a + b == 30, "a = {}, b = {}", a, b);
+/// ```
#[macro_export]
macro_rules! assert(
($cond:expr) => (
);
)
+/// Asserts that two expressions are equal to each other, testing equality in
+/// both directions.
+///
+/// On failure, this macro will print the values of the expressions.
+///
+/// # Example
+///
+/// ```
+/// let a = 3;
+/// let b = 1 + 2;
+/// assert_eq!(a, b);
+/// ```
#[macro_export]
macro_rules! assert_eq(
($given:expr , $expected:expr) => ({
/// # Example
///
/// ~~~rust
+/// struct Item { weight: uint }
+///
/// fn choose_weighted_item(v: &[Item]) -> Item {
/// assert!(!v.is_empty());
/// let mut so_far = 0u;
/// for item in v.iter() {
/// so_far += item.weight;
/// if so_far > 100 {
-/// return item;
+/// return *item;
/// }
/// }
/// // The above loop always returns, so we must hint to the
() => (fail!("not yet implemented"))
)
+/// Use the syntax described in `std::fmt` to create a value of type `~str`.
+/// See `std::fmt` for more information.
+///
+/// # Example
+///
+/// ```
+/// format!("test");
+/// format!("hello {}", "world!");
+/// format!("x = {}, y = {y}", 10, y = 30);
+/// ```
#[macro_export]
macro_rules! format(
($($arg:tt)*) => (
)
)
+/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`.
+/// See `std::fmt` for more information.
+///
+/// # Example
+///
+/// ```
+/// # #[allow(unused_must_use)];
+/// use std::io::MemWriter;
+///
+/// let mut w = MemWriter::new();
+/// write!(&mut w, "test");
+/// write!(&mut w, "formatted {}", "arguments");
+/// ```
#[macro_export]
macro_rules! write(
($dst:expr, $($arg:tt)*) => ({
})
)
+/// Equivalent to the `write!` macro, except that a newline is appended after
+/// the message is written.
#[macro_export]
macro_rules! writeln(
($dst:expr, $($arg:tt)*) => ({
})
)
+/// Equivalent to the `println!` macro except that a newline is not printed at
+/// the end of the message.
#[macro_export]
macro_rules! print(
($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*))
)
+/// Macro for printing to a task's stdout handle.
+///
+/// Each task can override its stdout handle via `std::io::stdio::set_stdout`.
+/// The syntax of this macro is the same as that used for `format!`. For more
+/// information, see `std::fmt` and `std::io::stdio`.
+///
+/// # Example
+///
+/// ```
+/// println!("hello there!");
+/// println!("format {} arguments", "some");
+/// ```
#[macro_export]
macro_rules! println(
($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*))
)
+/// Declare a task-local key with a specific type.
+///
+/// # Example
+///
+/// ```
+/// use std::local_data;
+///
+/// local_data_key!(my_integer: int)
+///
+/// local_data::set(my_integer, 2);
+/// local_data::get(my_integer, |val| println!("{}", val.map(|i| *i)));
+/// ```
#[macro_export]
macro_rules! local_data_key(
($name:ident: $ty:ty) => (
);
)
+/// Helper macro for unwrapping `Result` values while returning early with an
+/// error if the value of the expression is `Err`. For more information, see
+/// `std::io`.
#[macro_export]
macro_rules! if_ok(
($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
use unstable::intrinsics;
use unstable::intrinsics::{bswap16, bswap32, bswap64};
-/// Returns the size of a type
+/// Returns the size of a type in bytes.
#[inline]
pub fn size_of<T>() -> uint {
unsafe { intrinsics::size_of::<T>() }
}
-/// Returns the size of the type that `_val` points to
+/// Returns the size of the type that `_val` points to in bytes.
#[inline]
pub fn size_of_val<T>(_val: &T) -> uint {
size_of::<T>()
}
-/// Returns the size of a type, or 1 if the actual size is zero.
+/// Returns the size of a type in bytes, or 1 if the actual size is zero.
///
/// Useful for building structures containing variable-length arrays.
#[inline]
if s == 0 { 1 } else { s }
}
-/// Returns the size of the type of the value that `_val` points to
+/// Returns the size in bytes of the type of the value that `_val` points to.
#[inline]
pub fn nonzero_size_of_val<T>(_val: &T) -> uint {
nonzero_size_of::<T>()
// staticants from cmath.
// FIXME(#11621): These constants should be deprecated once CTFE is
- // implemented in favour of calling their respective functions in `Real`.
+ // implemented in favour of calling their respective functions in `Float`.
/// Archimedes' constant
pub static PI: f32 = 3.14159265358979323846264338327950288_f32;
fn fract(&self) -> f32 { *self - self.trunc() }
}
-impl Real for f32 {
+impl Bounded for f32 {
+ #[inline]
+ fn min_value() -> f32 { 1.17549435e-38 }
+
+ #[inline]
+ fn max_value() -> f32 { 3.40282347e+38 }
+}
+
+impl Primitive for f32 {}
+
+impl Float for f32 {
+ #[inline]
+ fn nan() -> f32 { 0.0 / 0.0 }
+
+ #[inline]
+ fn infinity() -> f32 { 1.0 / 0.0 }
+
+ #[inline]
+ fn neg_infinity() -> f32 { -1.0 / 0.0 }
+
+ #[inline]
+ fn neg_zero() -> f32 { -0.0 }
+
+ /// Returns `true` if the number is NaN
+ #[inline]
+ fn is_nan(&self) -> bool { *self != *self }
+
+ /// Returns `true` if the number is infinite
+ #[inline]
+ fn is_infinite(&self) -> bool {
+ *self == Float::infinity() || *self == Float::neg_infinity()
+ }
+
+ /// Returns `true` if the number is neither infinite or NaN
+ #[inline]
+ fn is_finite(&self) -> bool {
+ !(self.is_nan() || self.is_infinite())
+ }
+
+ /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
+ #[inline]
+ fn is_normal(&self) -> bool {
+ self.classify() == FPNormal
+ }
+
+ /// Returns the floating point category of the number. If only one property is going to
+ /// be tested, it is generally faster to use the specific predicate instead.
+ fn classify(&self) -> FPCategory {
+ static EXP_MASK: u32 = 0x7f800000;
+ static MAN_MASK: u32 = 0x007fffff;
+
+ match (
+ unsafe { ::cast::transmute::<f32,u32>(*self) } & MAN_MASK,
+ unsafe { ::cast::transmute::<f32,u32>(*self) } & EXP_MASK,
+ ) {
+ (0, 0) => FPZero,
+ (_, 0) => FPSubnormal,
+ (0, EXP_MASK) => FPInfinite,
+ (_, EXP_MASK) => FPNaN,
+ _ => FPNormal,
+ }
+ }
+
+ #[inline]
+ fn mantissa_digits(_: Option<f32>) -> uint { 24 }
+
+ #[inline]
+ fn digits(_: Option<f32>) -> uint { 6 }
+
+ #[inline]
+ fn epsilon() -> f32 { 1.19209290e-07 }
+
+ #[inline]
+ fn min_exp(_: Option<f32>) -> int { -125 }
+
+ #[inline]
+ fn max_exp(_: Option<f32>) -> int { 128 }
+
+ #[inline]
+ fn min_10_exp(_: Option<f32>) -> int { -37 }
+
+ #[inline]
+ fn max_10_exp(_: Option<f32>) -> int { 38 }
+
+ /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
+ #[inline]
+ fn ldexp(x: f32, exp: int) -> f32 {
+ ldexp(x, exp as c_int)
+ }
+
+ /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
+ ///
+ /// - `self = x * pow(2, exp)`
+ /// - `0.5 <= abs(x) < 1.0`
+ #[inline]
+ fn frexp(&self) -> (f32, int) {
+ let mut exp = 0;
+ let x = frexp(*self, &mut exp);
+ (x, exp as int)
+ }
+
+ /// Returns the exponential of the number, minus `1`, in a way that is accurate
+ /// even if the number is close to zero
+ #[inline]
+ fn exp_m1(&self) -> f32 { exp_m1(*self) }
+
+ /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
+ /// than if the operations were performed separately
+ #[inline]
+ fn ln_1p(&self) -> f32 { ln_1p(*self) }
+
+ /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
+ /// produces a more accurate result with better performance than a separate multiplication
+ /// operation followed by an add.
+ #[inline]
+ fn mul_add(&self, a: f32, b: f32) -> f32 {
+ mul_add(*self, a, b)
+ }
+
+ /// Returns the next representable floating-point value in the direction of `other`
+ #[inline]
+ fn next_after(&self, other: f32) -> f32 {
+ next_after(*self, other)
+ }
+
+ /// Returns the mantissa, exponent and sign as integers.
+ fn integer_decode(&self) -> (u64, i16, i8) {
+ let bits: u32 = unsafe {
+ ::cast::transmute(*self)
+ };
+ let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
+ let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
+ let mantissa = if exponent == 0 {
+ (bits & 0x7fffff) << 1
+ } else {
+ (bits & 0x7fffff) | 0x800000
+ };
+ // Exponent bias + mantissa shift
+ exponent -= 127 + 23;
+ (mantissa as u64, exponent, sign)
+ }
+
/// Archimedes' constant
#[inline]
fn pi() -> f32 { 3.14159265358979323846264338327950288 }
/// Converts to degrees, assuming the number is in radians
#[inline]
- fn to_degrees(&self) -> f32 { *self * (180.0f32 / Real::pi()) }
+ fn to_degrees(&self) -> f32 { *self * (180.0f32 / Float::pi()) }
/// Converts to radians, assuming the number is in degrees
#[inline]
fn to_radians(&self) -> f32 {
- let value: f32 = Real::pi();
+ let value: f32 = Float::pi();
*self * (value / 180.0f32)
}
}
-impl Bounded for f32 {
- #[inline]
- fn min_value() -> f32 { 1.17549435e-38 }
-
- #[inline]
- fn max_value() -> f32 { 3.40282347e+38 }
-}
-
-impl Primitive for f32 {}
-
-impl Float for f32 {
- #[inline]
- fn nan() -> f32 { 0.0 / 0.0 }
-
- #[inline]
- fn infinity() -> f32 { 1.0 / 0.0 }
-
- #[inline]
- fn neg_infinity() -> f32 { -1.0 / 0.0 }
-
- #[inline]
- fn neg_zero() -> f32 { -0.0 }
-
- /// Returns `true` if the number is NaN
- #[inline]
- fn is_nan(&self) -> bool { *self != *self }
-
- /// Returns `true` if the number is infinite
- #[inline]
- fn is_infinite(&self) -> bool {
- *self == Float::infinity() || *self == Float::neg_infinity()
- }
-
- /// Returns `true` if the number is neither infinite or NaN
- #[inline]
- fn is_finite(&self) -> bool {
- !(self.is_nan() || self.is_infinite())
- }
-
- /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
- #[inline]
- fn is_normal(&self) -> bool {
- self.classify() == FPNormal
- }
-
- /// Returns the floating point category of the number. If only one property is going to
- /// be tested, it is generally faster to use the specific predicate instead.
- fn classify(&self) -> FPCategory {
- static EXP_MASK: u32 = 0x7f800000;
- static MAN_MASK: u32 = 0x007fffff;
-
- match (
- unsafe { ::cast::transmute::<f32,u32>(*self) } & MAN_MASK,
- unsafe { ::cast::transmute::<f32,u32>(*self) } & EXP_MASK,
- ) {
- (0, 0) => FPZero,
- (_, 0) => FPSubnormal,
- (0, EXP_MASK) => FPInfinite,
- (_, EXP_MASK) => FPNaN,
- _ => FPNormal,
- }
- }
-
- #[inline]
- fn mantissa_digits(_: Option<f32>) -> uint { 24 }
-
- #[inline]
- fn digits(_: Option<f32>) -> uint { 6 }
-
- #[inline]
- fn epsilon() -> f32 { 1.19209290e-07 }
-
- #[inline]
- fn min_exp(_: Option<f32>) -> int { -125 }
-
- #[inline]
- fn max_exp(_: Option<f32>) -> int { 128 }
-
- #[inline]
- fn min_10_exp(_: Option<f32>) -> int { -37 }
-
- #[inline]
- fn max_10_exp(_: Option<f32>) -> int { 38 }
-
- /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
- #[inline]
- fn ldexp(x: f32, exp: int) -> f32 {
- ldexp(x, exp as c_int)
- }
-
- /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
- ///
- /// - `self = x * pow(2, exp)`
- /// - `0.5 <= abs(x) < 1.0`
- #[inline]
- fn frexp(&self) -> (f32, int) {
- let mut exp = 0;
- let x = frexp(*self, &mut exp);
- (x, exp as int)
- }
-
- /// Returns the exponential of the number, minus `1`, in a way that is accurate
- /// even if the number is close to zero
- #[inline]
- fn exp_m1(&self) -> f32 { exp_m1(*self) }
-
- /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
- /// than if the operations were performed separately
- #[inline]
- fn ln_1p(&self) -> f32 { ln_1p(*self) }
-
- /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
- /// produces a more accurate result with better performance than a separate multiplication
- /// operation followed by an add.
- #[inline]
- fn mul_add(&self, a: f32, b: f32) -> f32 {
- mul_add(*self, a, b)
- }
-
- /// Returns the next representable floating-point value in the direction of `other`
- #[inline]
- fn next_after(&self, other: f32) -> f32 {
- next_after(*self, other)
- }
-
- /// Returns the mantissa, exponent and sign as integers.
- fn integer_decode(&self) -> (u64, i16, i8) {
- let bits: u32 = unsafe {
- ::cast::transmute(*self)
- };
- let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
- let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
- let mantissa = if exponent == 0 {
- (bits & 0x7fffff) << 1
- } else {
- (bits & 0x7fffff) | 0x800000
- };
- // Exponent bias + mantissa shift
- exponent -= 127 + 23;
- (mantissa as u64, exponent, sign)
- }
-}
-
//
// Section: String Conversions
//
#[test]
fn test_real_consts() {
- let pi: f32 = Real::pi();
- let two_pi: f32 = Real::two_pi();
- let frac_pi_2: f32 = Real::frac_pi_2();
- let frac_pi_3: f32 = Real::frac_pi_3();
- let frac_pi_4: f32 = Real::frac_pi_4();
- let frac_pi_6: f32 = Real::frac_pi_6();
- let frac_pi_8: f32 = Real::frac_pi_8();
- let frac_1_pi: f32 = Real::frac_1_pi();
- let frac_2_pi: f32 = Real::frac_2_pi();
- let frac_2_sqrtpi: f32 = Real::frac_2_sqrtpi();
- let sqrt2: f32 = Real::sqrt2();
- let frac_1_sqrt2: f32 = Real::frac_1_sqrt2();
- let e: f32 = Real::e();
- let log2_e: f32 = Real::log2_e();
- let log10_e: f32 = Real::log10_e();
- let ln_2: f32 = Real::ln_2();
- let ln_10: f32 = Real::ln_10();
+ let pi: f32 = Float::pi();
+ let two_pi: f32 = Float::two_pi();
+ let frac_pi_2: f32 = Float::frac_pi_2();
+ let frac_pi_3: f32 = Float::frac_pi_3();
+ let frac_pi_4: f32 = Float::frac_pi_4();
+ let frac_pi_6: f32 = Float::frac_pi_6();
+ let frac_pi_8: f32 = Float::frac_pi_8();
+ let frac_1_pi: f32 = Float::frac_1_pi();
+ let frac_2_pi: f32 = Float::frac_2_pi();
+ let frac_2_sqrtpi: f32 = Float::frac_2_sqrtpi();
+ let sqrt2: f32 = Float::sqrt2();
+ let frac_1_sqrt2: f32 = Float::frac_1_sqrt2();
+ let e: f32 = Float::e();
+ let log2_e: f32 = Float::log2_e();
+ let log10_e: f32 = Float::log10_e();
+ let ln_2: f32 = Float::ln_2();
+ let ln_10: f32 = Float::ln_10();
assert_approx_eq!(two_pi, 2f32 * pi);
assert_approx_eq!(frac_pi_2, pi / 2f32);
// constants from cmath.
// FIXME(#11621): These constants should be deprecated once CTFE is
- // implemented in favour of calling their respective functions in `Real`.
+ // implemented in favour of calling their respective functions in `Float`.
/// Archimedes' constant
pub static PI: f64 = 3.14159265358979323846264338327950288_f64;
fn fract(&self) -> f64 { *self - self.trunc() }
}
-impl Real for f64 {
+impl Bounded for f64 {
+ #[inline]
+ fn min_value() -> f64 { 2.2250738585072014e-308 }
+
+ #[inline]
+ fn max_value() -> f64 { 1.7976931348623157e+308 }
+}
+
+impl Primitive for f64 {}
+
+impl Float for f64 {
+ #[inline]
+ fn nan() -> f64 { 0.0 / 0.0 }
+
+ #[inline]
+ fn infinity() -> f64 { 1.0 / 0.0 }
+
+ #[inline]
+ fn neg_infinity() -> f64 { -1.0 / 0.0 }
+
+ #[inline]
+ fn neg_zero() -> f64 { -0.0 }
+
+ /// Returns `true` if the number is NaN
+ #[inline]
+ fn is_nan(&self) -> bool { *self != *self }
+
+ /// Returns `true` if the number is infinite
+ #[inline]
+ fn is_infinite(&self) -> bool {
+ *self == Float::infinity() || *self == Float::neg_infinity()
+ }
+
+ /// Returns `true` if the number is neither infinite or NaN
+ #[inline]
+ fn is_finite(&self) -> bool {
+ !(self.is_nan() || self.is_infinite())
+ }
+
+ /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
+ #[inline]
+ fn is_normal(&self) -> bool {
+ self.classify() == FPNormal
+ }
+
+ /// Returns the floating point category of the number. If only one property is going to
+ /// be tested, it is generally faster to use the specific predicate instead.
+ fn classify(&self) -> FPCategory {
+ static EXP_MASK: u64 = 0x7ff0000000000000;
+ static MAN_MASK: u64 = 0x000fffffffffffff;
+
+ match (
+ unsafe { ::cast::transmute::<f64,u64>(*self) } & MAN_MASK,
+ unsafe { ::cast::transmute::<f64,u64>(*self) } & EXP_MASK,
+ ) {
+ (0, 0) => FPZero,
+ (_, 0) => FPSubnormal,
+ (0, EXP_MASK) => FPInfinite,
+ (_, EXP_MASK) => FPNaN,
+ _ => FPNormal,
+ }
+ }
+
+ #[inline]
+ fn mantissa_digits(_: Option<f64>) -> uint { 53 }
+
+ #[inline]
+ fn digits(_: Option<f64>) -> uint { 15 }
+
+ #[inline]
+ fn epsilon() -> f64 { 2.2204460492503131e-16 }
+
+ #[inline]
+ fn min_exp(_: Option<f64>) -> int { -1021 }
+
+ #[inline]
+ fn max_exp(_: Option<f64>) -> int { 1024 }
+
+ #[inline]
+ fn min_10_exp(_: Option<f64>) -> int { -307 }
+
+ #[inline]
+ fn max_10_exp(_: Option<f64>) -> int { 308 }
+
+ /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
+ #[inline]
+ fn ldexp(x: f64, exp: int) -> f64 {
+ ldexp(x, exp as c_int)
+ }
+
+ /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
+ ///
+ /// - `self = x * pow(2, exp)`
+ /// - `0.5 <= abs(x) < 1.0`
+ #[inline]
+ fn frexp(&self) -> (f64, int) {
+ let mut exp = 0;
+ let x = frexp(*self, &mut exp);
+ (x, exp as int)
+ }
+
+ /// Returns the exponential of the number, minus `1`, in a way that is accurate
+ /// even if the number is close to zero
+ #[inline]
+ fn exp_m1(&self) -> f64 { exp_m1(*self) }
+
+ /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
+ /// than if the operations were performed separately
+ #[inline]
+ fn ln_1p(&self) -> f64 { ln_1p(*self) }
+
+ /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
+ /// produces a more accurate result with better performance than a separate multiplication
+ /// operation followed by an add.
+ #[inline]
+ fn mul_add(&self, a: f64, b: f64) -> f64 {
+ mul_add(*self, a, b)
+ }
+
+ /// Returns the next representable floating-point value in the direction of `other`
+ #[inline]
+ fn next_after(&self, other: f64) -> f64 {
+ next_after(*self, other)
+ }
+
+ /// Returns the mantissa, exponent and sign as integers.
+ fn integer_decode(&self) -> (u64, i16, i8) {
+ let bits: u64 = unsafe {
+ ::cast::transmute(*self)
+ };
+ let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
+ let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
+ let mantissa = if exponent == 0 {
+ (bits & 0xfffffffffffff) << 1
+ } else {
+ (bits & 0xfffffffffffff) | 0x10000000000000
+ };
+ // Exponent bias + mantissa shift
+ exponent -= 1023 + 52;
+ (mantissa, exponent, sign)
+ }
+
/// Archimedes' constant
#[inline]
fn pi() -> f64 { 3.14159265358979323846264338327950288 }
/// Converts to degrees, assuming the number is in radians
#[inline]
- fn to_degrees(&self) -> f64 { *self * (180.0f64 / Real::pi()) }
+ fn to_degrees(&self) -> f64 { *self * (180.0f64 / Float::pi()) }
/// Converts to radians, assuming the number is in degrees
#[inline]
fn to_radians(&self) -> f64 {
- let value: f64 = Real::pi();
+ let value: f64 = Float::pi();
*self * (value / 180.0)
}
}
-impl Bounded for f64 {
- #[inline]
- fn min_value() -> f64 { 2.2250738585072014e-308 }
-
- #[inline]
- fn max_value() -> f64 { 1.7976931348623157e+308 }
-}
-
-impl Primitive for f64 {}
-
-impl Float for f64 {
- #[inline]
- fn nan() -> f64 { 0.0 / 0.0 }
-
- #[inline]
- fn infinity() -> f64 { 1.0 / 0.0 }
-
- #[inline]
- fn neg_infinity() -> f64 { -1.0 / 0.0 }
-
- #[inline]
- fn neg_zero() -> f64 { -0.0 }
-
- /// Returns `true` if the number is NaN
- #[inline]
- fn is_nan(&self) -> bool { *self != *self }
-
- /// Returns `true` if the number is infinite
- #[inline]
- fn is_infinite(&self) -> bool {
- *self == Float::infinity() || *self == Float::neg_infinity()
- }
-
- /// Returns `true` if the number is neither infinite or NaN
- #[inline]
- fn is_finite(&self) -> bool {
- !(self.is_nan() || self.is_infinite())
- }
-
- /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
- #[inline]
- fn is_normal(&self) -> bool {
- self.classify() == FPNormal
- }
-
- /// Returns the floating point category of the number. If only one property is going to
- /// be tested, it is generally faster to use the specific predicate instead.
- fn classify(&self) -> FPCategory {
- static EXP_MASK: u64 = 0x7ff0000000000000;
- static MAN_MASK: u64 = 0x000fffffffffffff;
-
- match (
- unsafe { ::cast::transmute::<f64,u64>(*self) } & MAN_MASK,
- unsafe { ::cast::transmute::<f64,u64>(*self) } & EXP_MASK,
- ) {
- (0, 0) => FPZero,
- (_, 0) => FPSubnormal,
- (0, EXP_MASK) => FPInfinite,
- (_, EXP_MASK) => FPNaN,
- _ => FPNormal,
- }
- }
-
- #[inline]
- fn mantissa_digits(_: Option<f64>) -> uint { 53 }
-
- #[inline]
- fn digits(_: Option<f64>) -> uint { 15 }
-
- #[inline]
- fn epsilon() -> f64 { 2.2204460492503131e-16 }
-
- #[inline]
- fn min_exp(_: Option<f64>) -> int { -1021 }
-
- #[inline]
- fn max_exp(_: Option<f64>) -> int { 1024 }
-
- #[inline]
- fn min_10_exp(_: Option<f64>) -> int { -307 }
-
- #[inline]
- fn max_10_exp(_: Option<f64>) -> int { 308 }
-
- /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
- #[inline]
- fn ldexp(x: f64, exp: int) -> f64 {
- ldexp(x, exp as c_int)
- }
-
- /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
- ///
- /// - `self = x * pow(2, exp)`
- /// - `0.5 <= abs(x) < 1.0`
- #[inline]
- fn frexp(&self) -> (f64, int) {
- let mut exp = 0;
- let x = frexp(*self, &mut exp);
- (x, exp as int)
- }
-
- /// Returns the exponential of the number, minus `1`, in a way that is accurate
- /// even if the number is close to zero
- #[inline]
- fn exp_m1(&self) -> f64 { exp_m1(*self) }
-
- /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
- /// than if the operations were performed separately
- #[inline]
- fn ln_1p(&self) -> f64 { ln_1p(*self) }
-
- /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
- /// produces a more accurate result with better performance than a separate multiplication
- /// operation followed by an add.
- #[inline]
- fn mul_add(&self, a: f64, b: f64) -> f64 {
- mul_add(*self, a, b)
- }
-
- /// Returns the next representable floating-point value in the direction of `other`
- #[inline]
- fn next_after(&self, other: f64) -> f64 {
- next_after(*self, other)
- }
-
- /// Returns the mantissa, exponent and sign as integers.
- fn integer_decode(&self) -> (u64, i16, i8) {
- let bits: u64 = unsafe {
- ::cast::transmute(*self)
- };
- let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
- let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
- let mantissa = if exponent == 0 {
- (bits & 0xfffffffffffff) << 1
- } else {
- (bits & 0xfffffffffffff) | 0x10000000000000
- };
- // Exponent bias + mantissa shift
- exponent -= 1023 + 52;
- (mantissa, exponent, sign)
- }
-}
-
//
// Section: String Conversions
//
#[test]
fn test_real_consts() {
- let pi: f64 = Real::pi();
- let two_pi: f64 = Real::two_pi();
- let frac_pi_2: f64 = Real::frac_pi_2();
- let frac_pi_3: f64 = Real::frac_pi_3();
- let frac_pi_4: f64 = Real::frac_pi_4();
- let frac_pi_6: f64 = Real::frac_pi_6();
- let frac_pi_8: f64 = Real::frac_pi_8();
- let frac_1_pi: f64 = Real::frac_1_pi();
- let frac_2_pi: f64 = Real::frac_2_pi();
- let frac_2_sqrtpi: f64 = Real::frac_2_sqrtpi();
- let sqrt2: f64 = Real::sqrt2();
- let frac_1_sqrt2: f64 = Real::frac_1_sqrt2();
- let e: f64 = Real::e();
- let log2_e: f64 = Real::log2_e();
- let log10_e: f64 = Real::log10_e();
- let ln_2: f64 = Real::ln_2();
- let ln_10: f64 = Real::ln_10();
+ let pi: f64 = Float::pi();
+ let two_pi: f64 = Float::two_pi();
+ let frac_pi_2: f64 = Float::frac_pi_2();
+ let frac_pi_3: f64 = Float::frac_pi_3();
+ let frac_pi_4: f64 = Float::frac_pi_4();
+ let frac_pi_6: f64 = Float::frac_pi_6();
+ let frac_pi_8: f64 = Float::frac_pi_8();
+ let frac_1_pi: f64 = Float::frac_1_pi();
+ let frac_2_pi: f64 = Float::frac_2_pi();
+ let frac_2_sqrtpi: f64 = Float::frac_2_sqrtpi();
+ let sqrt2: f64 = Float::sqrt2();
+ let frac_1_sqrt2: f64 = Float::frac_1_sqrt2();
+ let e: f64 = Float::e();
+ let log2_e: f64 = Float::log2_e();
+ let log10_e: f64 = Float::log10_e();
+ let ln_2: f64 = Float::ln_2();
+ let ln_10: f64 = Float::ln_10();
assert_approx_eq!(two_pi, 2.0 * pi);
assert_approx_eq!(frac_pi_2, pi / 2f64);
fn fract(&self) -> Self;
}
-/// Defines constants and methods common to real numbers
-pub trait Real: Signed
- + Ord
- + Round
- + Div<Self,Self> {
- // Common Constants
- // FIXME (#5527): These should be associated constants
- fn pi() -> Self;
- fn two_pi() -> Self;
- fn frac_pi_2() -> Self;
- fn frac_pi_3() -> Self;
- fn frac_pi_4() -> Self;
- fn frac_pi_6() -> Self;
- fn frac_pi_8() -> Self;
- fn frac_1_pi() -> Self;
- fn frac_2_pi() -> Self;
- fn frac_2_sqrtpi() -> Self;
- fn sqrt2() -> Self;
- fn frac_1_sqrt2() -> Self;
- fn e() -> Self;
- fn log2_e() -> Self;
- fn log10_e() -> Self;
- fn ln_2() -> Self;
- fn ln_10() -> Self;
-
- // Fractional functions
-
- /// Take the reciprocal (inverse) of a number, `1/x`.
- fn recip(&self) -> Self;
-
- // Algebraic functions
- /// Raise a number to a power.
- fn powf(&self, n: &Self) -> Self;
-
- /// Take the square root of a number.
- fn sqrt(&self) -> Self;
- /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`.
- fn rsqrt(&self) -> Self;
- /// Take the cubic root of a number.
- fn cbrt(&self) -> Self;
- /// Calculate the length of the hypotenuse of a right-angle triangle given
- /// legs of length `x` and `y`.
- fn hypot(&self, other: &Self) -> Self;
-
- // Trigonometric functions
-
- /// Computes the sine of a number (in radians).
- fn sin(&self) -> Self;
- /// Computes the cosine of a number (in radians).
- fn cos(&self) -> Self;
- /// Computes the tangent of a number (in radians).
- fn tan(&self) -> Self;
-
- /// Computes the arcsine of a number. Return value is in radians in
- /// the range [-pi/2, pi/2] or NaN if the number is outside the range
- /// [-1, 1].
- fn asin(&self) -> Self;
- /// Computes the arccosine of a number. Return value is in radians in
- /// the range [0, pi] or NaN if the number is outside the range
- /// [-1, 1].
- fn acos(&self) -> Self;
- /// Computes the arctangent of a number. Return value is in radians in the
- /// range [-pi/2, pi/2];
- fn atan(&self) -> Self;
- /// Computes the four quadrant arctangent of a number, `y`, and another
- /// number `x`. Return value is in radians in the range [-pi, pi].
- fn atan2(&self, other: &Self) -> Self;
- /// Simultaneously computes the sine and cosine of the number, `x`. Returns
- /// `(sin(x), cos(x))`.
- fn sin_cos(&self) -> (Self, Self);
-
- // Exponential functions
-
- /// Returns `e^(self)`, (the exponential function).
- fn exp(&self) -> Self;
- /// Returns 2 raised to the power of the number, `2^(self)`.
- fn exp2(&self) -> Self;
- /// Returns the natural logarithm of the number.
- fn ln(&self) -> Self;
- /// Returns the logarithm of the number with respect to an arbitrary base.
- fn log(&self, base: &Self) -> Self;
- /// Returns the base 2 logarithm of the number.
- fn log2(&self) -> Self;
- /// Returns the base 10 logarithm of the number.
- fn log10(&self) -> Self;
-
- // Hyperbolic functions
-
- /// Hyperbolic sine function.
- fn sinh(&self) -> Self;
- /// Hyperbolic cosine function.
- fn cosh(&self) -> Self;
- /// Hyperbolic tangent function.
- fn tanh(&self) -> Self;
- /// Inverse hyperbolic sine function.
- fn asinh(&self) -> Self;
- /// Inverse hyperbolic cosine function.
- fn acosh(&self) -> Self;
- /// Inverse hyperbolic tangent function.
- fn atanh(&self) -> Self;
-
- // Angular conversions
-
- /// Convert radians to degrees.
- fn to_degrees(&self) -> Self;
- /// Convert degrees to radians.
- fn to_radians(&self) -> Self;
-}
-
/// Raises a value to the power of exp, using exponentiation by squaring.
///
/// # Example
}
}
-/// Raise a number to a power.
-///
-/// # Example
-///
-/// ```rust
-/// use std::num;
-///
-/// let sixteen: f64 = num::powf(2.0, 4.0);
-/// assert_eq!(sixteen, 16.0);
-/// ```
-#[inline(always)] pub fn powf<T: Real>(value: T, n: T) -> T { value.powf(&n) }
-/// Take the square root of a number.
-#[inline(always)] pub fn sqrt<T: Real>(value: T) -> T { value.sqrt() }
-/// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`.
-#[inline(always)] pub fn rsqrt<T: Real>(value: T) -> T { value.rsqrt() }
-/// Take the cubic root of a number.
-#[inline(always)] pub fn cbrt<T: Real>(value: T) -> T { value.cbrt() }
-/// Calculate the length of the hypotenuse of a right-angle triangle given legs of length `x` and
-/// `y`.
-#[inline(always)] pub fn hypot<T: Real>(x: T, y: T) -> T { x.hypot(&y) }
-/// Sine function.
-#[inline(always)] pub fn sin<T: Real>(value: T) -> T { value.sin() }
-/// Cosine function.
-#[inline(always)] pub fn cos<T: Real>(value: T) -> T { value.cos() }
-/// Tangent function.
-#[inline(always)] pub fn tan<T: Real>(value: T) -> T { value.tan() }
-/// Compute the arcsine of the number.
-#[inline(always)] pub fn asin<T: Real>(value: T) -> T { value.asin() }
-/// Compute the arccosine of the number.
-#[inline(always)] pub fn acos<T: Real>(value: T) -> T { value.acos() }
-/// Compute the arctangent of the number.
-#[inline(always)] pub fn atan<T: Real>(value: T) -> T { value.atan() }
-/// Compute the arctangent with 2 arguments.
-#[inline(always)] pub fn atan2<T: Real>(x: T, y: T) -> T { x.atan2(&y) }
-/// Simultaneously computes the sine and cosine of the number.
-#[inline(always)] pub fn sin_cos<T: Real>(value: T) -> (T, T) { value.sin_cos() }
-/// Returns `e^(value)`, (the exponential function).
-#[inline(always)] pub fn exp<T: Real>(value: T) -> T { value.exp() }
-/// Returns 2 raised to the power of the number, `2^(value)`.
-#[inline(always)] pub fn exp2<T: Real>(value: T) -> T { value.exp2() }
-/// Returns the natural logarithm of the number.
-#[inline(always)] pub fn ln<T: Real>(value: T) -> T { value.ln() }
-/// Returns the logarithm of the number with respect to an arbitrary base.
-#[inline(always)] pub fn log<T: Real>(value: T, base: T) -> T { value.log(&base) }
-/// Returns the base 2 logarithm of the number.
-#[inline(always)] pub fn log2<T: Real>(value: T) -> T { value.log2() }
-/// Returns the base 10 logarithm of the number.
-#[inline(always)] pub fn log10<T: Real>(value: T) -> T { value.log10() }
-/// Hyperbolic sine function.
-#[inline(always)] pub fn sinh<T: Real>(value: T) -> T { value.sinh() }
-/// Hyperbolic cosine function.
-#[inline(always)] pub fn cosh<T: Real>(value: T) -> T { value.cosh() }
-/// Hyperbolic tangent function.
-#[inline(always)] pub fn tanh<T: Real>(value: T) -> T { value.tanh() }
-/// Inverse hyperbolic sine function.
-#[inline(always)] pub fn asinh<T: Real>(value: T) -> T { value.asinh() }
-/// Inverse hyperbolic cosine function.
-#[inline(always)] pub fn acosh<T: Real>(value: T) -> T { value.acosh() }
-/// Inverse hyperbolic tangent function.
-#[inline(always)] pub fn atanh<T: Real>(value: T) -> T { value.atanh() }
-
pub trait Bounded {
// FIXME (#5527): These should be associated constants
fn min_value() -> Self;
}
/// Primitive floating point numbers
-pub trait Float: Real
- + Signed
+pub trait Float: Signed
+ + Round
+ Primitive {
// FIXME (#5527): These should be associated constants
fn nan() -> Self;
fn next_after(&self, other: Self) -> Self;
fn integer_decode(&self) -> (u64, i16, i8);
+
+ // Common Mathematical Constants
+ // FIXME (#5527): These should be associated constants
+ fn pi() -> Self;
+ fn two_pi() -> Self;
+ fn frac_pi_2() -> Self;
+ fn frac_pi_3() -> Self;
+ fn frac_pi_4() -> Self;
+ fn frac_pi_6() -> Self;
+ fn frac_pi_8() -> Self;
+ fn frac_1_pi() -> Self;
+ fn frac_2_pi() -> Self;
+ fn frac_2_sqrtpi() -> Self;
+ fn sqrt2() -> Self;
+ fn frac_1_sqrt2() -> Self;
+ fn e() -> Self;
+ fn log2_e() -> Self;
+ fn log10_e() -> Self;
+ fn ln_2() -> Self;
+ fn ln_10() -> Self;
+
+ // Fractional functions
+
+ /// Take the reciprocal (inverse) of a number, `1/x`.
+ fn recip(&self) -> Self;
+
+ // Algebraic functions
+ /// Raise a number to a power.
+ fn powf(&self, n: &Self) -> Self;
+
+ /// Take the square root of a number.
+ fn sqrt(&self) -> Self;
+ /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`.
+ fn rsqrt(&self) -> Self;
+ /// Take the cubic root of a number.
+ fn cbrt(&self) -> Self;
+ /// Calculate the length of the hypotenuse of a right-angle triangle given
+ /// legs of length `x` and `y`.
+ fn hypot(&self, other: &Self) -> Self;
+
+ // Trigonometric functions
+
+ /// Computes the sine of a number (in radians).
+ fn sin(&self) -> Self;
+ /// Computes the cosine of a number (in radians).
+ fn cos(&self) -> Self;
+ /// Computes the tangent of a number (in radians).
+ fn tan(&self) -> Self;
+
+ /// Computes the arcsine of a number. Return value is in radians in
+ /// the range [-pi/2, pi/2] or NaN if the number is outside the range
+ /// [-1, 1].
+ fn asin(&self) -> Self;
+ /// Computes the arccosine of a number. Return value is in radians in
+ /// the range [0, pi] or NaN if the number is outside the range
+ /// [-1, 1].
+ fn acos(&self) -> Self;
+ /// Computes the arctangent of a number. Return value is in radians in the
+ /// range [-pi/2, pi/2];
+ fn atan(&self) -> Self;
+ /// Computes the four quadrant arctangent of a number, `y`, and another
+ /// number `x`. Return value is in radians in the range [-pi, pi].
+ fn atan2(&self, other: &Self) -> Self;
+ /// Simultaneously computes the sine and cosine of the number, `x`. Returns
+ /// `(sin(x), cos(x))`.
+ fn sin_cos(&self) -> (Self, Self);
+
+ // Exponential functions
+
+ /// Returns `e^(self)`, (the exponential function).
+ fn exp(&self) -> Self;
+ /// Returns 2 raised to the power of the number, `2^(self)`.
+ fn exp2(&self) -> Self;
+ /// Returns the natural logarithm of the number.
+ fn ln(&self) -> Self;
+ /// Returns the logarithm of the number with respect to an arbitrary base.
+ fn log(&self, base: &Self) -> Self;
+ /// Returns the base 2 logarithm of the number.
+ fn log2(&self) -> Self;
+ /// Returns the base 10 logarithm of the number.
+ fn log10(&self) -> Self;
+
+ // Hyperbolic functions
+
+ /// Hyperbolic sine function.
+ fn sinh(&self) -> Self;
+ /// Hyperbolic cosine function.
+ fn cosh(&self) -> Self;
+ /// Hyperbolic tangent function.
+ fn tanh(&self) -> Self;
+ /// Inverse hyperbolic sine function.
+ fn asinh(&self) -> Self;
+ /// Inverse hyperbolic cosine function.
+ fn acosh(&self) -> Self;
+ /// Inverse hyperbolic tangent function.
+ fn atanh(&self) -> Self;
+
+ // Angular conversions
+
+ /// Convert radians to degrees.
+ fn to_degrees(&self) -> Self;
+ /// Convert degrees to radians.
+ fn to_radians(&self) -> Self;
}
/// Returns the exponential of the number, minus `1`, `exp(n) - 1`, in a way
/// architectures) than a separate multiplication operation followed by an add.
#[inline(always)] pub fn mul_add<T: Float>(a: T, b: T, c: T) -> T { a.mul_add(b, c) }
+/// Raise a number to a power.
+///
+/// # Example
+///
+/// ```rust
+/// use std::num;
+///
+/// let sixteen: f64 = num::powf(2.0, 4.0);
+/// assert_eq!(sixteen, 16.0);
+/// ```
+#[inline(always)] pub fn powf<T: Float>(value: T, n: T) -> T { value.powf(&n) }
+/// Take the square root of a number.
+#[inline(always)] pub fn sqrt<T: Float>(value: T) -> T { value.sqrt() }
+/// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`.
+#[inline(always)] pub fn rsqrt<T: Float>(value: T) -> T { value.rsqrt() }
+/// Take the cubic root of a number.
+#[inline(always)] pub fn cbrt<T: Float>(value: T) -> T { value.cbrt() }
+/// Calculate the length of the hypotenuse of a right-angle triangle given legs
+/// of length `x` and `y`.
+#[inline(always)] pub fn hypot<T: Float>(x: T, y: T) -> T { x.hypot(&y) }
+/// Sine function.
+#[inline(always)] pub fn sin<T: Float>(value: T) -> T { value.sin() }
+/// Cosine function.
+#[inline(always)] pub fn cos<T: Float>(value: T) -> T { value.cos() }
+/// Tangent function.
+#[inline(always)] pub fn tan<T: Float>(value: T) -> T { value.tan() }
+/// Compute the arcsine of the number.
+#[inline(always)] pub fn asin<T: Float>(value: T) -> T { value.asin() }
+/// Compute the arccosine of the number.
+#[inline(always)] pub fn acos<T: Float>(value: T) -> T { value.acos() }
+/// Compute the arctangent of the number.
+#[inline(always)] pub fn atan<T: Float>(value: T) -> T { value.atan() }
+/// Compute the arctangent with 2 arguments.
+#[inline(always)] pub fn atan2<T: Float>(x: T, y: T) -> T { x.atan2(&y) }
+/// Simultaneously computes the sine and cosine of the number.
+#[inline(always)] pub fn sin_cos<T: Float>(value: T) -> (T, T) { value.sin_cos() }
+/// Returns `e^(value)`, (the exponential function).
+#[inline(always)] pub fn exp<T: Float>(value: T) -> T { value.exp() }
+/// Returns 2 raised to the power of the number, `2^(value)`.
+#[inline(always)] pub fn exp2<T: Float>(value: T) -> T { value.exp2() }
+/// Returns the natural logarithm of the number.
+#[inline(always)] pub fn ln<T: Float>(value: T) -> T { value.ln() }
+/// Returns the logarithm of the number with respect to an arbitrary base.
+#[inline(always)] pub fn log<T: Float>(value: T, base: T) -> T { value.log(&base) }
+/// Returns the base 2 logarithm of the number.
+#[inline(always)] pub fn log2<T: Float>(value: T) -> T { value.log2() }
+/// Returns the base 10 logarithm of the number.
+#[inline(always)] pub fn log10<T: Float>(value: T) -> T { value.log10() }
+/// Hyperbolic sine function.
+#[inline(always)] pub fn sinh<T: Float>(value: T) -> T { value.sinh() }
+/// Hyperbolic cosine function.
+#[inline(always)] pub fn cosh<T: Float>(value: T) -> T { value.cosh() }
+/// Hyperbolic tangent function.
+#[inline(always)] pub fn tanh<T: Float>(value: T) -> T { value.tanh() }
+/// Inverse hyperbolic sine function.
+#[inline(always)] pub fn asinh<T: Float>(value: T) -> T { value.asinh() }
+/// Inverse hyperbolic cosine function.
+#[inline(always)] pub fn acosh<T: Float>(value: T) -> T { value.acosh() }
+/// Inverse hyperbolic tangent function.
+#[inline(always)] pub fn atanh<T: Float>(value: T) -> T { value.atanh() }
+
/// A generic trait for converting a value to a number.
pub trait ToPrimitive {
/// Converts the value of `self` to an `int`.
fail!();
}
}
- Path::new(str::from_utf16(buf))
+ Path::new(str::from_utf16(str::truncate_utf16_at_nul(buf))
+ .expect("GetCurrentDirectoryW returned invalid UTF-16"))
}
#[cfg(windows)]
}
if k != 0 && done {
let sub = buf.slice(0, k as uint);
- res = option::Some(str::from_utf16(sub));
+ // We want to explicitly catch the case when the
+ // closure returned invalid UTF-16, rather than
+ // set `res` to None and continue.
+ let s = str::from_utf16(sub)
+ .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
+ res = option::Some(s)
}
}
return res;
fail!("[{}] FormatMessage failure", errno());
}
- str::from_utf16(buf)
+ str::from_utf16(str::truncate_utf16_at_nul(buf))
+ .expect("FormatMessageW returned invalid UTF-16")
}
}
while *ptr.offset(len as int) != 0 { len += 1; }
// Push it onto the list.
- args.push(vec::raw::buf_as_slice(ptr, len,
- str::from_utf16));
+ let opt_s = vec::raw::buf_as_slice(ptr, len, |buf| {
+ str::from_utf16(str::truncate_utf16_at_nul(buf))
+ });
+ args.push(opt_s.expect("CommandLineToArgvW returned invalid UTF-16"));
}
}
pub use iter::{FromIterator, Extendable};
pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator};
pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
-pub use num::{Integer, Real, Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
+pub use num::{Integer, Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
pub use num::{Signed, Unsigned, Round};
pub use num::{Primitive, Int, Float, ToStrRadix, ToPrimitive, FromPrimitive};
pub use path::{GenericPath, Path, PosixPath, WindowsPath};
//! The exponential distribution.
-use num::Real;
+use num::Float;
use rand::{Rng, Rand};
use rand::distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
//! The Gamma and derived distributions.
-use num::Real;
+use num::Float;
use num;
use rand::{Rng, Open01};
use super::normal::StandardNormal;
//! The normal and derived distributions.
-use num::Real;
+use num::Float;
use rand::{Rng, Rand, Open01};
use rand::distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
ops.deschedule(amt, self, f)
}
- /// Wakes up a previously blocked task, optionally specifiying whether the
+ /// Wakes up a previously blocked task, optionally specifying whether the
/// current task can accept a change in scheduling. This function can only
/// be called on tasks that were previously blocked in `deschedule`.
pub fn reawaken(mut ~self) {
/// The entry point for unwinding with a formatted message.
///
/// This is designed to reduce the amount of code required at the call
-/// site as much as possible (so that `fail!()` has as low an implact
+/// site as much as possible (so that `fail!()` has as low an impact
/// on (e.g.) the inlining of other functions as possible), by moving
/// the actual formatting into this shared place.
#[inline(never)] #[cold]
Section: Misc
*/
-/// Determines if a vector of bytes contains valid UTF-8
-pub fn is_utf8(v: &[u8]) -> bool {
- first_non_utf8_index(v).is_none()
-}
-
+/// Walk through `iter` checking that it's a valid UTF-8 sequence,
+/// returning `true` in that case, or, if it is invalid, `false` with
+/// `iter` reset such that it is pointing at the first byte in the
+/// invalid sequence.
#[inline(always)]
-fn first_non_utf8_index(v: &[u8]) -> Option<uint> {
- let mut i = 0u;
- let total = v.len();
- fn unsafe_get(xs: &[u8], i: uint) -> u8 {
- unsafe { *xs.unsafe_ref(i) }
- }
- while i < total {
- let v_i = unsafe_get(v, i);
- if v_i < 128u8 {
- i += 1u;
- } else {
- let w = utf8_char_width(v_i);
- if w == 0u { return Some(i); }
+fn run_utf8_validation_iterator(iter: &mut vec::Items<u8>) -> bool {
+ loop {
+ // save the current thing we're pointing at.
+ let old = *iter;
+
+ // restore the iterator we had at the start of this codepoint.
+ macro_rules! err ( () => { {*iter = old; return false} });
+ macro_rules! next ( () => {
+ match iter.next() {
+ Some(a) => *a,
+ // we needed data, but there was none: error!
+ None => err!()
+ }
+ });
- let nexti = i + w;
- if nexti > total { return Some(i); }
+ let first = match iter.next() {
+ Some(&b) => b,
+ // we're at the end of the iterator and a codepoint
+ // boundary at the same time, so this string is valid.
+ None => return true
+ };
+ // ASCII characters are always valid, so only large
+ // bytes need more examination.
+ if first >= 128 {
+ let w = utf8_char_width(first);
+ let second = next!();
// 2-byte encoding is for codepoints \u0080 to \u07ff
// first C2 80 last DF BF
// 3-byte encoding is for codepoints \u0800 to \uffff
// %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
// UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
// %xF4 %x80-8F 2( UTF8-tail )
- // UTF8-tail = %x80-BF
match w {
- 2 => if unsafe_get(v, i + 1) & 192u8 != TAG_CONT_U8 {
- return Some(i)
- },
- 3 => match (v_i,
- unsafe_get(v, i + 1),
- unsafe_get(v, i + 2) & 192u8) {
- (0xE0 , 0xA0 .. 0xBF, TAG_CONT_U8) => (),
- (0xE1 .. 0xEC, 0x80 .. 0xBF, TAG_CONT_U8) => (),
- (0xED , 0x80 .. 0x9F, TAG_CONT_U8) => (),
- (0xEE .. 0xEF, 0x80 .. 0xBF, TAG_CONT_U8) => (),
- _ => return Some(i),
- },
- _ => match (v_i,
- unsafe_get(v, i + 1),
- unsafe_get(v, i + 2) & 192u8,
- unsafe_get(v, i + 3) & 192u8) {
- (0xF0 , 0x90 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) => (),
- (0xF1 .. 0xF3, 0x80 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) => (),
- (0xF4 , 0x80 .. 0x8F, TAG_CONT_U8, TAG_CONT_U8) => (),
- _ => return Some(i)
- },
+ 2 => if second & 192 != TAG_CONT_U8 {err!()},
+ 3 => {
+ match (first, second, next!() & 192) {
+ (0xE0 , 0xA0 .. 0xBF, TAG_CONT_U8) |
+ (0xE1 .. 0xEC, 0x80 .. 0xBF, TAG_CONT_U8) |
+ (0xED , 0x80 .. 0x9F, TAG_CONT_U8) |
+ (0xEE .. 0xEF, 0x80 .. 0xBF, TAG_CONT_U8) => {}
+ _ => err!()
+ }
+ }
+ 4 => {
+ match (first, second, next!() & 192, next!() & 192) {
+ (0xF0 , 0x90 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
+ (0xF1 .. 0xF3, 0x80 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
+ (0xF4 , 0x80 .. 0x8F, TAG_CONT_U8, TAG_CONT_U8) => {}
+ _ => err!()
+ }
+ }
+ _ => err!()
}
-
- i = nexti;
}
}
- None
+}
+
+/// Determines if a vector of bytes contains valid UTF-8.
+pub fn is_utf8(v: &[u8]) -> bool {
+ run_utf8_validation_iterator(&mut v.iter())
+}
+
+#[inline(always)]
+fn first_non_utf8_index(v: &[u8]) -> Option<uint> {
+ let mut it = v.iter();
+
+ let ok = run_utf8_validation_iterator(&mut it);
+ if ok {
+ None
+ } else {
+ // work out how many valid bytes we've consumed
+ // (run_utf8_validation_iterator resets the iterator to just
+ // after the last good byte), which we can do because the
+ // vector iterator size_hint is exact.
+ let (remaining, _) = it.size_hint();
+ Some(v.len() - remaining)
+ }
}
/// Determines if a vector of `u16` contains valid UTF-16
pub fn is_utf16(v: &[u16]) -> bool {
- let len = v.len();
- let mut i = 0u;
- while i < len {
- let u = v[i];
+ let mut it = v.iter();
+ macro_rules! next ( ($ret:expr) => {
+ match it.next() { Some(u) => *u, None => return $ret }
+ }
+ )
+ loop {
+ let u = next!(true);
- if u <= 0xD7FF_u16 || u >= 0xE000_u16 {
- i += 1u;
+ match char::from_u32(u as u32) {
+ Some(_) => {}
+ None => {
+ let u2 = next!(false);
+ if u < 0xD7FF || u > 0xDBFF ||
+ u2 < 0xDC00 || u2 > 0xDFFF { return false; }
+ }
+ }
+ }
+}
+
+/// An iterator that decodes UTF-16 encoded codepoints from a vector
+/// of `u16`s.
+#[deriving(Clone)]
+pub struct UTF16Items<'a> {
+ priv iter: vec::Items<'a, u16>
+}
+/// The possibilities for values decoded from a `u16` stream.
+#[deriving(Eq, TotalEq, Clone)]
+pub enum UTF16Item {
+ /// A valid codepoint.
+ ScalarValue(char),
+ /// An invalid surrogate without its pair.
+ LoneSurrogate(u16)
+}
+impl UTF16Item {
+ /// Convert `self` to a `char`, taking `LoneSurrogate`s to the
+ /// replacement character (U+FFFD).
+ #[inline]
+ pub fn to_char_lossy(&self) -> char {
+ match *self {
+ ScalarValue(c) => c,
+ LoneSurrogate(_) => '\uFFFD'
+ }
+ }
+}
+
+impl<'a> Iterator<UTF16Item> for UTF16Items<'a> {
+ fn next(&mut self) -> Option<UTF16Item> {
+ let u = match self.iter.next() {
+ Some(u) => *u,
+ None => return None
+ };
+
+ if u < 0xD800 || 0xDFFF < u {
+ // not a surrogate
+ Some(ScalarValue(unsafe {cast::transmute(u as u32)}))
+ } else if u >= 0xDC00 {
+ // a trailing surrogate
+ Some(LoneSurrogate(u))
} else {
- if i+1u < len { return false; }
- let u2 = v[i+1u];
- if u < 0xD7FF_u16 || u > 0xDBFF_u16 { return false; }
- if u2 < 0xDC00_u16 || u2 > 0xDFFF_u16 { return false; }
- i += 2u;
+ // preserve state for rewinding.
+ let old = self.iter;
+
+ let u2 = match self.iter.next() {
+ Some(u2) => *u2,
+ // eof
+ None => return Some(LoneSurrogate(u))
+ };
+ if u2 < 0xDC00 || u2 > 0xDFFF {
+ // not a trailing surrogate so we're not a valid
+ // surrogate pair, so rewind to redecode u2 next time.
+ self.iter = old;
+ return Some(LoneSurrogate(u))
+ }
+
+ // all ok, so lets decode it.
+ let c = ((u - 0xD800) as u32 << 10 | (u2 - 0xDC00) as u32) + 0x1_0000;
+ Some(ScalarValue(unsafe {cast::transmute(c)}))
}
}
- return true;
+
+ #[inline]
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let (low, high) = self.iter.size_hint();
+ // we could be entirely valid surrogates (2 elements per
+ // char), or entirely non-surrogates (1 element per char)
+ (low / 2, high)
+ }
}
-/// Iterates over the utf-16 characters in the specified slice, yielding each
-/// decoded unicode character to the function provided.
+/// Create an iterator over the UTF-16 encoded codepoints in `v`,
+/// returning invalid surrogates as `LoneSurrogate`s.
///
-/// # Failures
+/// # Example
///
-/// * Fails on invalid utf-16 data
-pub fn utf16_chars(v: &[u16], f: |char|) {
- let len = v.len();
- let mut i = 0u;
- while i < len && v[i] != 0u16 {
- let u = v[i];
-
- if u <= 0xD7FF_u16 || u >= 0xE000_u16 {
- f(unsafe { cast::transmute(u as u32) });
- i += 1u;
+/// ```rust
+/// use std::str;
+/// use std::str::{ScalarValue, LoneSurrogate};
+///
+/// // 𝄞mus<invalid>ic<invalid>
+/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075,
+/// 0x0073, 0xDD1E, 0x0069, 0x0063,
+/// 0xD834];
+///
+/// assert_eq!(str::utf16_items(v).to_owned_vec(),
+/// ~[ScalarValue('𝄞'),
+/// ScalarValue('m'), ScalarValue('u'), ScalarValue('s'),
+/// LoneSurrogate(0xDD1E),
+/// ScalarValue('i'), ScalarValue('c'),
+/// LoneSurrogate(0xD834)]);
+/// ```
+pub fn utf16_items<'a>(v: &'a [u16]) -> UTF16Items<'a> {
+ UTF16Items { iter : v.iter() }
+}
- } else {
- let u2 = v[i+1u];
- assert!(u >= 0xD800_u16 && u <= 0xDBFF_u16);
- assert!(u2 >= 0xDC00_u16 && u2 <= 0xDFFF_u16);
- let mut c: u32 = (u - 0xD800_u16) as u32;
- c = c << 10;
- c |= (u2 - 0xDC00_u16) as u32;
- c |= 0x1_0000_u32;
- f(unsafe { cast::transmute(c) });
- i += 2u;
+/// Return a slice of `v` ending at (and not including) the first NUL
+/// (0).
+///
+/// # Example
+///
+/// ```rust
+/// use std::str;
+///
+/// // "abcd"
+/// let mut v = ['a' as u16, 'b' as u16, 'c' as u16, 'd' as u16];
+/// // no NULs so no change
+/// assert_eq!(str::truncate_utf16_at_nul(v), v.as_slice());
+///
+/// // "ab\0d"
+/// v[2] = 0;
+/// assert_eq!(str::truncate_utf16_at_nul(v),
+/// &['a' as u16, 'b' as u16]);
+/// ```
+pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
+ match v.iter().position(|c| *c == 0) {
+ // don't include the 0
+ Some(i) => v.slice_to(i),
+ None => v
+ }
+}
+
+/// Decode a UTF-16 encoded vector `v` into a string, returning `None`
+/// if `v` contains any invalid data.
+///
+/// # Example
+///
+/// ```rust
+/// use std::str;
+///
+/// // 𝄞music
+/// let mut v = [0xD834, 0xDD1E, 0x006d, 0x0075,
+/// 0x0073, 0x0069, 0x0063];
+/// assert_eq!(str::from_utf16(v), Some(~"𝄞music"));
+///
+/// // 𝄞mu<invalid>ic
+/// v[4] = 0xD800;
+/// assert_eq!(str::from_utf16(v), None);
+/// ```
+pub fn from_utf16(v: &[u16]) -> Option<~str> {
+ let mut s = with_capacity(v.len() / 2);
+ for c in utf16_items(v) {
+ match c {
+ ScalarValue(c) => s.push_char(c),
+ LoneSurrogate(_) => return None
}
}
+ Some(s)
}
-/// Allocates a new string from the utf-16 slice provided
-pub fn from_utf16(v: &[u16]) -> ~str {
- let mut buf = with_capacity(v.len());
- utf16_chars(v, |ch| buf.push_char(ch));
- buf
+/// Decode a UTF-16 encoded vector `v` into a string, replacing
+/// invalid data with the replacement character (U+FFFD).
+///
+/// # Example
+/// ```rust
+/// use std::str;
+///
+/// // 𝄞mus<invalid>ic<invalid>
+/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075,
+/// 0x0073, 0xDD1E, 0x0069, 0x0063,
+/// 0xD834];
+///
+/// assert_eq!(str::from_utf16_lossy(v),
+/// ~"𝄞mus\uFFFDic\uFFFD");
+/// ```
+pub fn from_utf16_lossy(v: &[u16]) -> ~str {
+ utf16_items(v).map(|c| c.to_char_lossy()).collect()
}
/// Allocates a new string with the specified capacity. The string returned is
assert!(is_utf8([0xF4, 0x8F, 0xBF, 0xBF]));
}
+ #[test]
+ fn test_is_utf16() {
+ macro_rules! pos ( ($($e:expr),*) => { { $(assert!(is_utf16($e));)* } });
+
+ // non-surrogates
+ pos!([0x0000],
+ [0x0001, 0x0002],
+ [0xD7FF],
+ [0xE000]);
+
+ // surrogate pairs (randomly generated with Python 3's
+ // .encode('utf-16be'))
+ pos!([0xdb54, 0xdf16, 0xd880, 0xdee0, 0xdb6a, 0xdd45],
+ [0xd91f, 0xdeb1, 0xdb31, 0xdd84, 0xd8e2, 0xde14],
+ [0xdb9f, 0xdc26, 0xdb6f, 0xde58, 0xd850, 0xdfae]);
+
+ // mixtures (also random)
+ pos!([0xd921, 0xdcc2, 0x002d, 0x004d, 0xdb32, 0xdf65],
+ [0xdb45, 0xdd2d, 0x006a, 0xdacd, 0xddfe, 0x0006],
+ [0x0067, 0xd8ff, 0xddb7, 0x000f, 0xd900, 0xdc80]);
+
+ // negative tests
+ macro_rules! neg ( ($($e:expr),*) => { { $(assert!(!is_utf16($e));)* } });
+
+ neg!(
+ // surrogate + regular unit
+ [0xdb45, 0x0000],
+ // surrogate + lead surrogate
+ [0xd900, 0xd900],
+ // unterminated surrogate
+ [0xd8ff],
+ // trail surrogate without a lead
+ [0xddb7]);
+
+ // random byte sequences that Python 3's .decode('utf-16be')
+ // failed on
+ neg!([0x5b3d, 0x0141, 0xde9e, 0x8fdc, 0xc6e7],
+ [0xdf5a, 0x82a5, 0x62b9, 0xb447, 0x92f3],
+ [0xda4e, 0x42bc, 0x4462, 0xee98, 0xc2ca],
+ [0xbe00, 0xb04a, 0x6ecb, 0xdd89, 0xe278],
+ [0x0465, 0xab56, 0xdbb6, 0xa893, 0x665e],
+ [0x6b7f, 0x0a19, 0x40f4, 0xa657, 0xdcc5],
+ [0x9b50, 0xda5e, 0x24ec, 0x03ad, 0x6dee],
+ [0x8d17, 0xcaa7, 0xf4ae, 0xdf6e, 0xbed7],
+ [0xdaee, 0x2584, 0x7d30, 0xa626, 0x121a],
+ [0xd956, 0x4b43, 0x7570, 0xccd6, 0x4f4a],
+ [0x9dcf, 0x1b49, 0x4ba5, 0xfce9, 0xdffe],
+ [0x6572, 0xce53, 0xb05a, 0xf6af, 0xdacf],
+ [0x1b90, 0x728c, 0x9906, 0xdb68, 0xf46e],
+ [0x1606, 0xbeca, 0xbe76, 0x860f, 0xdfa5],
+ [0x8b4f, 0xde7a, 0xd220, 0x9fac, 0x2b6f],
+ [0xb8fe, 0xebbe, 0xda32, 0x1a5f, 0x8b8b],
+ [0x934b, 0x8956, 0xc434, 0x1881, 0xddf7],
+ [0x5a95, 0x13fc, 0xf116, 0xd89b, 0x93f9],
+ [0xd640, 0x71f1, 0xdd7d, 0x77eb, 0x1cd8],
+ [0x348b, 0xaef0, 0xdb2c, 0xebf1, 0x1282],
+ [0x50d7, 0xd824, 0x5010, 0xb369, 0x22ea]);
+ }
+
#[test]
fn test_raw_from_c_str() {
unsafe {
0xdc9c_u16, 0xd801_u16, 0xdc92_u16, 0xd801_u16,
0xdc96_u16, 0xd801_u16, 0xdc86_u16, 0x0020_u16,
0xd801_u16, 0xdc95_u16, 0xd801_u16, 0xdc86_u16,
- 0x000a_u16 ]) ];
+ 0x000a_u16 ]),
+ // Issue #12318, even-numbered non-BMP planes
+ (~"\U00020000",
+ ~[0xD840, 0xDC00])];
for p in pairs.iter() {
let (s, u) = (*p).clone();
- assert!(s.to_utf16() == u);
- assert!(from_utf16(u) == s);
- assert!(from_utf16(s.to_utf16()) == s);
- assert!(from_utf16(u).to_utf16() == u);
+ assert!(is_utf16(u));
+ assert_eq!(s.to_utf16(), u);
+
+ assert_eq!(from_utf16(u).unwrap(), s);
+ assert_eq!(from_utf16_lossy(u), s);
+
+ assert_eq!(from_utf16(s.to_utf16()).unwrap(), s);
+ assert_eq!(from_utf16(u).unwrap().to_utf16(), u);
}
}
+ #[test]
+ fn test_utf16_invalid() {
+ // completely positive cases tested above.
+ // lead + eof
+ assert_eq!(from_utf16([0xD800]), None);
+ // lead + lead
+ assert_eq!(from_utf16([0xD800, 0xD800]), None);
+
+ // isolated trail
+ assert_eq!(from_utf16([0x0061, 0xDC00]), None);
+
+ // general
+ assert_eq!(from_utf16([0xD800, 0xd801, 0xdc8b, 0xD800]), None);
+ }
+
+ #[test]
+ fn test_utf16_lossy() {
+ // completely positive cases tested above.
+ // lead + eof
+ assert_eq!(from_utf16_lossy([0xD800]), ~"\uFFFD");
+ // lead + lead
+ assert_eq!(from_utf16_lossy([0xD800, 0xD800]), ~"\uFFFD\uFFFD");
+
+ // isolated trail
+ assert_eq!(from_utf16_lossy([0x0061, 0xDC00]), ~"a\uFFFD");
+
+ // general
+ assert_eq!(from_utf16_lossy([0xD800, 0xd801, 0xdc8b, 0xD800]), ~"\uFFFD𐒋\uFFFD");
+ }
+
+ #[test]
+ fn test_truncate_utf16_at_nul() {
+ let v = [];
+ assert_eq!(truncate_utf16_at_nul(v), &[]);
+
+ let v = [0, 2, 3];
+ assert_eq!(truncate_utf16_at_nul(v), &[]);
+
+ let v = [1, 0, 3];
+ assert_eq!(truncate_utf16_at_nul(v), &[1]);
+
+ let v = [1, 2, 0];
+ assert_eq!(truncate_utf16_at_nul(v), &[1, 2]);
+
+ let v = [1, 2, 3];
+ assert_eq!(truncate_utf16_at_nul(v), &[1, 2, 3]);
+ }
+
#[test]
fn test_char_at() {
let s = ~"ศไทย中华Việt Nam";
///
/// Note that the current implementation means that this function cannot
/// return `Option<T>`. It is possible for this queue to be in an
- /// inconsistent state where many pushes have suceeded and completely
+ /// inconsistent state where many pushes have succeeded and completely
/// finished, but pops cannot return `Some(t)`. This inconsistent state
/// happens when a pusher is pre-empted at an inopportune moment.
///
}
}
}
-
//! Runtime calls emitted by the compiler.
-use c_str::ToCStr;
+use c_str::CString;
+use libc::c_char;
+use cast;
+use option::Some;
#[cold]
#[lang="fail_"]
pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
let msg = format!("index out of bounds: the len is {} but the index is {}",
len as uint, index as uint);
- msg.with_c_str(|buf| fail_(buf as *u8, file, line))
+
+ let file_str = match unsafe { CString::new(file as *c_char, false) }.as_str() {
+ // This transmute is safe because `file` is always stored in rodata.
+ Some(s) => unsafe { cast::transmute::<&str, &'static str>(s) },
+ None => "file wasn't UTF-8 safe"
+ };
+
+ ::rt::begin_unwind(msg, file_str, line)
}
#[lang="malloc"]
* other tasks wishing to access the data will block until the closure
* finishes running.
*
- * The reason this function is 'unsafe' is because it is possible to
- * construct a circular reference among multiple Arcs by mutating the
- * underlying data. This creates potential for deadlock, but worse, this
- * will guarantee a memory leak of all involved Arcs. Using MutexArcs
- * inside of other Arcs is safe in absence of circular references.
- *
* If you wish to nest MutexArcs, one strategy for ensuring safety at
* runtime is to add a "nesting level counter" inside the stored data, and
* when traversing the arcs, assert that they monotonically decrease.
* blocked on the mutex) will also fail immediately.
*/
#[inline]
- pub unsafe fn unsafe_access<U>(&self, blk: |x: &mut T| -> U) -> U {
+ pub fn access<U>(&self, blk: |x: &mut T| -> U) -> U {
let state = self.x.get();
- // Borrowck would complain about this if the function were
- // not already unsafe. See borrow_rwlock, far below.
- (&(*state).lock).lock(|| {
- check_poison(true, (*state).failed);
- let _z = PoisonOnFail::new(&mut (*state).failed);
- blk(&mut (*state).data)
- })
+ unsafe {
+ // Borrowck would complain about this if the code were
+ // not already unsafe. See borrow_rwlock, far below.
+ (&(*state).lock).lock(|| {
+ check_poison(true, (*state).failed);
+ let _z = PoisonOnFail::new(&mut (*state).failed);
+ blk(&mut (*state).data)
+ })
+ }
}
- /// As unsafe_access(), but with a condvar, as sync::mutex.lock_cond().
+ /// As access(), but with a condvar, as sync::mutex.lock_cond().
#[inline]
- pub unsafe fn unsafe_access_cond<U>(&self,
- blk: |x: &mut T, c: &Condvar| -> U)
- -> U {
+ pub fn access_cond<U>(&self, blk: |x: &mut T, c: &Condvar| -> U) -> U {
let state = self.x.get();
- (&(*state).lock).lock_cond(|cond| {
- check_poison(true, (*state).failed);
- let _z = PoisonOnFail::new(&mut (*state).failed);
- blk(&mut (*state).data,
- &Condvar {is_mutex: true,
- failed: &(*state).failed,
- cond: cond })
- })
- }
-}
-
-impl<T:Freeze + Send> MutexArc<T> {
-
- /**
- * As unsafe_access.
- *
- * The difference between access and unsafe_access is that the former
- * forbids mutexes to be nested. While unsafe_access can be used on
- * MutexArcs without freezable interiors, this safe version of access
- * requires the Freeze bound, which prohibits access on MutexArcs which
- * might contain nested MutexArcs inside.
- *
- * The purpose of this is to offer a safe implementation of MutexArc to be
- * used instead of RWArc in cases where no readers are needed and slightly
- * better performance is required.
- *
- * Both methods have the same failure behaviour as unsafe_access and
- * unsafe_access_cond.
- */
- #[inline]
- pub fn access<U>(&self, blk: |x: &mut T| -> U) -> U {
- unsafe { self.unsafe_access(blk) }
- }
-
- /// As unsafe_access_cond but safe and Freeze.
- #[inline]
- pub fn access_cond<U>(&self,
- blk: |x: &mut T, c: &Condvar| -> U)
- -> U {
- unsafe { self.unsafe_access_cond(blk) }
+ unsafe {
+ (&(*state).lock).lock_cond(|cond| {
+ check_poison(true, (*state).failed);
+ let _z = PoisonOnFail::new(&mut (*state).failed);
+ blk(&mut (*state).data,
+ &Condvar {is_mutex: true,
+ failed: &(*state).failed,
+ cond: cond })
+ })
+ }
}
}
impl<T:Clone+Send+Freeze> Clone for CowArc<T> {
/// Duplicate a Copy-on-write Arc. See arc::clone for more details.
- #[inline]
fn clone(&self) -> CowArc<T> {
CowArc { x: self.x.clone() }
}
}
#[test]
- fn test_unsafe_mutex_arc_nested() {
- unsafe {
- // Tests nested mutexes and access
- // to underlaying data.
- let arc = ~MutexArc::new(1);
- let arc2 = ~MutexArc::new(*arc);
- task::spawn(proc() {
- (*arc2).unsafe_access(|mutex| {
- (*mutex).access(|one| {
- assert!(*one == 1);
- })
+ fn test_mutex_arc_nested() {
+ // Tests nested mutexes and access
+ // to underlaying data.
+ let arc = ~MutexArc::new(1);
+ let arc2 = ~MutexArc::new(*arc);
+ task::spawn(proc() {
+ (*arc2).access(|mutex| {
+ (*mutex).access(|one| {
+ assert!(*one == 1);
})
- });
- }
+ })
+ });
}
#[test]
/// Acquires a mutex, blocking the current task until it is able to do so.
///
- /// This function will block the local task until it is availble to acquire
+ /// This function will block the local task until it is available to acquire
/// the mutex. Upon returning, the task is the only task with the mutex
/// held. An RAII guard is returned to allow scoped unlock of the lock. When
/// the guard goes out of scope, the mutex will be unlocked.
"inline assembly must be a string literal.") {
Some((s, st)) => (s, st),
// let compilation continue
- None => return MacResult::dummy_expr(),
+ None => return MacResult::dummy_expr(sp),
};
asm = s;
asm_str_style = Some(style);
fn make_stmt(&self) -> @ast::Stmt;
}
+
pub enum MacResult {
MRExpr(@ast::Expr),
MRItem(@ast::Item),
/// type signatures after emitting a non-fatal error (which stop
/// compilation well before the validity (or otherwise)) of the
/// expression are checked.
- pub fn dummy_expr() -> MacResult {
- MRExpr(@ast::Expr {
- id: ast::DUMMY_NODE_ID, node: ast::ExprLogLevel, span: codemap::DUMMY_SP
- })
+ pub fn raw_dummy_expr(sp: codemap::Span) -> @ast::Expr {
+ @ast::Expr {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ExprLogLevel,
+ span: sp
+ }
+ }
+ pub fn dummy_expr(sp: codemap::Span) -> MacResult {
+ MRExpr(MacResult::raw_dummy_expr(sp))
}
}
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult {
// Gather all argument expressions
let exprs = match get_exprs_from_tts(cx, sp, tts) {
- None => return MacResult::dummy_expr(),
+ None => return MacResult::dummy_expr(sp),
Some(e) => e,
};
let mut bytes = ~[];
tts: &[ast::TokenTree]) -> base::MacResult {
let es = match base::get_exprs_from_tts(cx, sp, tts) {
Some(e) => e,
- None => return base::MacResult::dummy_expr()
+ None => return base::MacResult::dummy_expr(sp)
};
let mut accumulator = ~"";
for e in es.move_iter() {
ast::TTTok(_, token::COMMA) => (),
_ => {
cx.span_err(sp, "concat_idents! expecting comma.");
- return MacResult::dummy_expr();
+ return MacResult::dummy_expr(sp);
}
}
} else {
}
_ => {
cx.span_err(sp, "concat_idents! requires ident args.");
- return MacResult::dummy_expr();
+ return MacResult::dummy_expr(sp);
}
}
}
pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-> base::MacResult {
let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") {
- None => return MacResult::dummy_expr(),
+ None => return MacResult::dummy_expr(sp),
Some(v) => v
};
let exprs = match get_exprs_from_tts(cx, sp, tts) {
Some([]) => {
cx.span_err(sp, "env! takes 1 or 2 arguments");
- return MacResult::dummy_expr();
+ return MacResult::dummy_expr(sp);
}
- None => return MacResult::dummy_expr(),
+ None => return MacResult::dummy_expr(sp),
Some(exprs) => exprs
};
let var = match expr_to_str(cx, exprs[0], "expected string literal") {
- None => return MacResult::dummy_expr(),
+ None => return MacResult::dummy_expr(sp),
Some((v, _style)) => v
};
let msg = match exprs.len() {
}
2 => {
match expr_to_str(cx, exprs[1], "expected string literal") {
- None => return MacResult::dummy_expr(),
+ None => return MacResult::dummy_expr(sp),
Some((s, _style)) => s
}
}
_ => {
cx.span_err(sp, "env! takes 1 or 2 arguments");
- return MacResult::dummy_expr();
+ return MacResult::dummy_expr(sp);
}
};
format!("expected macro name without module \
separators"));
// let compilation continue
- return e;
+ return MacResult::raw_dummy_expr(e.span);
}
let extname = pth.segments[0].identifier;
let extnamestr = token::get_ident(extname);
extnamestr.get()));
// let compilation continue
- return e;
+ return MacResult::raw_dummy_expr(e.span);
}
Some(&NormalTT(ref expandfun, exp_span)) => {
fld.cx.bt_push(ExpnInfo {
extnamestr.get()
)
);
- return e;
+ return MacResult::raw_dummy_expr(e.span);
}
};
format!("'{}' is not a tt-style macro",
extnamestr.get())
);
- return e;
+ return MacResult::raw_dummy_expr(e.span);
}
};
let mut lets = ~[];
let mut locals = ~[];
let mut names = vec::from_fn(self.name_positions.len(), |_| None);
+ let mut pats = ~[];
+ let mut heads = ~[];
// First, declare all of our methods that are statics
for &method in self.method_statics.iter() {
if self.arg_types[i].is_none() { continue } // error already generated
let name = self.ecx.ident_of(format!("__arg{}", i));
- let e = self.ecx.expr_addr_of(e.span, e);
- lets.push(self.ecx.stmt_let(e.span, false, name, e));
+ pats.push(self.ecx.pat_ident(e.span, name));
+ heads.push(self.ecx.expr_addr_of(e.span, e));
locals.push(self.format_arg(e.span, Exact(i),
self.ecx.expr_ident(e.span, name)));
}
}
let lname = self.ecx.ident_of(format!("__arg{}", *name));
- let e = self.ecx.expr_addr_of(e.span, e);
- lets.push(self.ecx.stmt_let(e.span, false, lname, e));
+ pats.push(self.ecx.pat_ident(e.span, lname));
+ heads.push(self.ecx.expr_addr_of(e.span, e));
names[*self.name_positions.get(name)] =
Some(self.format_arg(e.span,
Named((*name).clone()),
let res = self.ecx.expr_ident(self.fmtsp, resname);
let result = self.ecx.expr_call(extra.span, extra, ~[
self.ecx.expr_addr_of(extra.span, res)]);
- self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
- Some(result)))
+ let body = self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
+ Some(result)));
+
+ // Constructs an AST equivalent to:
+ //
+ // match (&arg0, &arg1) {
+ // (tmp0, tmp1) => body
+ // }
+ //
+ // It was:
+ //
+ // let tmp0 = &arg0;
+ // let tmp1 = &arg1;
+ // body
+ //
+ // Because of #11585 the new temporary lifetime rule, the enclosing
+ // statements for these temporaries become the let's themselves.
+ // If one or more of them are RefCell's, RefCell borrow() will also
+ // end there; they don't last long enough for body to use them. The
+ // match expression solves the scope problem.
+ //
+ // Note, it may also very well be transformed to:
+ //
+ // match arg0 {
+ // ref tmp0 => {
+ // match arg1 => {
+ // ref tmp1 => body } } }
+ //
+ // But the nested match expression is proved to perform not as well
+ // as series of let's; the first approach does.
+ let pat = self.ecx.pat(self.fmtsp, ast::PatTup(pats));
+ let arm = self.ecx.arm(self.fmtsp, ~[pat], body);
+ let head = self.ecx.expr(self.fmtsp, ast::ExprTup(heads));
+ self.ecx.expr_match(self.fmtsp, head, ~[arm])
}
fn format_arg(&self, sp: Span, argno: Position, arg: @ast::Expr)
expr,
"format argument must be a string literal.") {
Some((fmt, _)) => fmt,
- None => return efmt
+ None => return MacResult::raw_dummy_expr(sp)
};
let mut parser = parse::Parser::new(fmt.get());
match parser.errors.shift() {
Some(error) => {
cx.ecx.span_err(efmt.span, "invalid format string: " + error);
- return efmt;
+ return MacResult::raw_dummy_expr(sp);
}
None => {}
}
-> base::MacResult {
let file = match get_single_str_from_tts(cx, sp, tts, "include!") {
Some(f) => f,
- None => return MacResult::dummy_expr(),
+ None => return MacResult::dummy_expr(sp),
};
// The file will be added to the code map by the parser
let mut p =
-> base::MacResult {
let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
Some(f) => f,
- None => return MacResult::dummy_expr()
+ None => return MacResult::dummy_expr(sp)
};
let file = res_rel_file(cx, sp, &Path::new(file));
let bytes = match File::open(&file).read_to_end() {
Err(e) => {
cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
- return MacResult::dummy_expr();
+ return MacResult::dummy_expr(sp);
}
Ok(bytes) => bytes,
};
}
None => {
cx.span_err(sp, format!("{} wasn't a utf-8 file", file.display()));
- return MacResult::dummy_expr();
+ return MacResult::dummy_expr(sp);
}
}
}
{
let file = match get_single_str_from_tts(cx, sp, tts, "include_bin!") {
Some(f) => f,
- None => return MacResult::dummy_expr()
+ None => return MacResult::dummy_expr(sp)
};
let file = res_rel_file(cx, sp, &Path::new(file));
match File::open(&file).read_to_end() {
Err(e) => {
cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
- return MacResult::dummy_expr();
+ return MacResult::dummy_expr(sp);
}
Ok(bytes) => {
base::MRExpr(cx.expr_lit(sp, ast::LitBinary(Rc::new(bytes))))
cx.set_trace_macros(false);
} else {
cx.span_err(sp, "trace_macros! only accepts `true` or `false`");
- return base::MacResult::dummy_expr();
+ return base::MacResult::dummy_expr(sp);
}
rust_parser.bump();
--- /dev/null
+// 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.
+
+fn main() {
+ print!(test!());
+ //~^ ERROR: macro undefined: 'test'
+ //~^^ ERROR: format argument must be a string literal
+
+ concat!(test!());
+ //~^ ERROR: macro undefined: 'test'
+ //~^^ ERROR: expected a literal
+}
fn get_tw_map<'lt>(tw: &'lt TraitWrapper) -> &'lt MyTrait {
match *tw {
- A(~ref map) => map, //~ ERROR found a ~-box pattern
+ A(~ref map) => map, //~ ERROR found a `~`-box pattern
}
}
match (true, false) {
~(true, false) => ()
- //~^ ERROR mismatched types: expected `(bool,bool)` but found a ~-box pattern
+ //~^ ERROR mismatched types: expected `(bool,bool)` but found a `~`-box pattern
}
match (true, false) {
&(true, false) => ()
- //~^ ERROR mismatched types: expected `(bool,bool)` but found an &-pointer pattern
+ //~^ ERROR mismatched types: expected `(bool,bool)` but found an `&`-pointer pattern
}
+++ /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.
-
-extern crate sync;
-
-use std::task;
-use sync::MutexArc;
-
-fn test_mutex_arc_nested() {
- let arc = ~MutexArc::new(1);
- let arc2 = ~MutexArc::new(*arc);
-
- task::spawn(proc() {
- (*arc2).access(|mutex| { //~ ERROR instantiating a type parameter with an incompatible type
- })
- });
-}
-
-fn main() {}
--- /dev/null
+// 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.
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+ pub trait Bar {
+ }
+ pub struct Baz;
+
+ fn Bar() { }
+}
+
+fn test_glob1() {
+ use foo1::*;
+
+ Bar(); //~ ERROR unresolved name `Bar`.
+}
+
+// private type, public value
+pub mod foo2 {
+ trait Bar {
+ }
+ pub struct Baz;
+
+ pub fn Bar() { }
+}
+
+fn test_glob2() {
+ use foo2::*;
+
+ let _x: ~Bar; //~ ERROR use of undeclared type name `Bar`
+}
+
+// neither public
+pub mod foo3 {
+ trait Bar {
+ }
+ pub struct Baz;
+
+ fn Bar() { }
+}
+
+fn test_glob3() {
+ use foo3::*;
+
+ Bar(); //~ ERROR unresolved name `Bar`.
+ let _x: ~Bar; //~ ERROR use of undeclared type name `Bar`
+}
+
+fn main() {
+}
+
--- /dev/null
+// 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.
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+ pub trait Bar {
+ }
+ pub struct Baz;
+
+ fn Bar() { }
+}
+
+fn test_single1() {
+ // In an ideal world, these would be private instead of inaccessible.
+ use foo1::Bar; //~ ERROR `Bar` is inaccessible
+
+ Bar();
+}
+
+fn test_list1() {
+ use foo1::{Bar,Baz}; //~ ERROR `Bar` is inaccessible
+
+ Bar();
+}
+
+// private type, public value
+pub mod foo2 {
+ trait Bar {
+ }
+ pub struct Baz;
+
+ pub fn Bar() { }
+}
+
+fn test_single2() {
+ use foo2::Bar; //~ ERROR `Bar` is private
+
+ let _x : ~Bar;
+}
+
+fn test_list2() {
+ use foo2::{Bar,Baz}; //~ ERROR `Bar` is private
+
+ let _x: ~Bar;
+}
+
+// neither public
+pub mod foo3 {
+ trait Bar {
+ }
+ pub struct Baz;
+
+ fn Bar() { }
+}
+
+fn test_unused3() {
+ use foo3::Bar; //~ ERROR `Bar` is private
+ use foo3::{Bar,Baz}; //~ ERROR `Bar` is private
+}
+
+fn test_single3() {
+ use foo3::Bar; //~ ERROR `Bar` is private
+
+ Bar();
+ let _x: ~Bar;
+}
+
+fn test_list3() {
+ use foo3::{Bar,Baz}; //~ ERROR `Bar` is private
+
+ Bar();
+ let _x: ~Bar;
+}
+
+fn main() {
+}
+
--- /dev/null
+-include ../tools.mk
+all:
+ $(RUSTDOC) -w json -o $(TMPDIR)/doc.json foo.rs
+ $(RUSTDOC) -o $(TMPDIR)/doc $(TMPDIR)/doc.json
--- /dev/null
+// 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.
+
+#[crate_id = "foo#0.1"];
+
+//! Very docs
+
+pub mod bar {
+
+ /// So correct
+ pub mod baz {
+ /// Much detail
+ pub fn baz() { }
+ }
+
+ /// *wow*
+ pub trait Doge { }
+}
--- /dev/null
+-include ../tools.mk
+
+all:
+ ar crus libfoo.a foo.rs
+ ar d libfoo.a foo.rs
+ $(RUSTC) foo.rs
--- /dev/null
+// 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.
+
+#[crate_type = "staticlib"];
+
+#[link(name = "foo", kind = "static")]
+extern {}
+
+fn main() {}
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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::RefCell;
+
+pub fn main() {
+ let name = RefCell::new("rust");
+ let what = RefCell::new("rocks");
+ let msg = format!("{name:?} {:?}", what.borrow().get(), name=name.borrow().get());
+ assert_eq!(msg, ~"&\"rust\" &\"rocks\"");
+}
--- /dev/null
+// 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.
+
+// Regresion test for issue 7660
+// rvalue lifetime too short when equivalent `match` works
+
+use std::hashmap::HashMap;
+
+struct A(int, int);
+
+pub fn main() {
+ let mut m: HashMap<int, A> = HashMap::new();
+ m.insert(1, A(0, 0));
+
+ let A(ref _a, ref _b) = *m.get(&1);
+ let (a, b) = match *m.get(&1) { A(ref _a, ref _b) => (_a, _b) };
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-fast
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+ pub trait Bar {
+ }
+ pub struct Baz;
+
+ fn Bar() { }
+}
+
+fn test_unused1() {
+ use foo1::Bar;
+ use foo1::{Bar,Baz};
+ use foo1::*;
+}
+
+fn test_single1() {
+ use foo1::Bar;
+
+ let _x: ~Bar;
+}
+
+fn test_list1() {
+ use foo1::{Bar,Baz};
+
+ let _x: ~Bar;
+}
+
+fn test_glob1() {
+ use foo1::*;
+
+ let _x: ~Bar;
+}
+
+// private type, public value
+pub mod foo2 {
+ trait Bar {
+ }
+ pub struct Baz;
+
+ pub fn Bar() { }
+}
+
+fn test_unused2() {
+ use foo2::Bar;
+ use foo2::{Bar,Baz};
+ use foo2::*;
+}
+
+fn test_single2() {
+ use foo2::Bar;
+
+ Bar();
+}
+
+fn test_list2() {
+ use foo2::{Bar,Baz};
+
+ Bar();
+}
+
+fn test_glob2() {
+ use foo2::*;
+
+ Bar();
+}
+
+// public type, public value
+pub mod foo3 {
+ pub trait Bar {
+ }
+ pub struct Baz;
+
+ pub fn Bar() { }
+}
+
+fn test_unused3() {
+ use foo3::Bar;
+ use foo3::{Bar,Baz};
+ use foo3::*;
+}
+
+fn test_single3() {
+ use foo3::Bar;
+
+ Bar();
+ let _x: ~Bar;
+}
+
+fn test_list3() {
+ use foo3::{Bar,Baz};
+
+ Bar();
+ let _x: ~Bar;
+}
+
+fn test_glob3() {
+ use foo3::*;
+
+ Bar();
+ let _x: ~Bar;
+}
+
+fn main() {
+}
+
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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.
+
+// Ensure assigning an owned or managed variable to itself works. In particular,
+// that we do not glue_drop before we glue_take (#3290).
+
+use std::rc::Rc;
+
+pub fn main() {
+ let mut x = ~3;
+ x = x;
+ assert!(*x == 3);
+
+ let mut x = Rc::new(3);
+ x = x;
+ assert!(*x.borrow() == 3);
+}