Skip to content

Commit

Permalink
Auto merge of #35100 - GuillaumeGomez:rollup, r=GuillaumeGomez
Browse files Browse the repository at this point in the history
Rollup of 7 pull requests

- Successful merges: #34258, #34894, #35050, #35062, #35066, #35072, #35087
- Failed merges:
  • Loading branch information
bors authored Jul 29, 2016
2 parents 1523a54 + 5f5fdf6 commit 5a7773a
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 27 deletions.
6 changes: 3 additions & 3 deletions src/doc/book/closures.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,9 @@ isn’t interesting. The next part is:
# some_closure(1) }
```

Because `Fn` is a trait, we can bound our generic with it. In this case, our
closure takes a `i32` as an argument and returns an `i32`, and so the generic
bound we use is `Fn(i32) -> i32`.
Because `Fn` is a trait, we can use it as a bound for our generic type. In
this case, our closure takes a `i32` as an argument and returns an `i32`, and
so the generic bound we use is `Fn(i32) -> i32`.

There’s one other key point here: because we’re bounding a generic with a
trait, this will get monomorphized, and therefore, we’ll be doing static
Expand Down
73 changes: 63 additions & 10 deletions src/doc/book/ffi.md
Original file line number Diff line number Diff line change
Expand Up @@ -575,16 +575,69 @@ against `libc` and `libm` by default.

# The "nullable pointer optimization"

Certain types are defined to not be NULL. This includes references (`&T`,
`&mut T`), boxes (`Box<T>`), and function pointers (`extern "abi" fn()`).
When interfacing with C, pointers that might be NULL are often used.
As a special case, a generic `enum` that contains exactly two variants, one of
which contains no data and the other containing a single field, is eligible
for the "nullable pointer optimization". When such an enum is instantiated
with one of the non-nullable types, it is represented as a single pointer,
and the non-data variant is represented as the NULL pointer. So
`Option<extern "C" fn(c_int) -> c_int>` is how one represents a nullable
function pointer using the C ABI.
Certain Rust types are defined to never be `null`. This includes references (`&T`,
`&mut T`), boxes (`Box<T>`), and function pointers (`extern "abi" fn()`). When
interfacing with C, pointers that might be `null` are often used, which would seem to
require some messy `transmute`s and/or unsafe code to handle conversions to/from Rust types.
However, the language provides a workaround.

As a special case, an `enum` is eligible for the "nullable pointer optimization" if it contains
exactly two variants, one of which contains no data and the other contains a field of one of the
non-nullable types listed above. This means no extra space is required for a discriminant; rather,
the empty variant is represented by putting a `null` value into the non-nullable field. This is
called an "optimization", but unlike other optimizations it is guaranteed to apply to eligible
types.

The most common type that takes advantage of the nullable pointer optimization is `Option<T>`,
where `None` corresponds to `null`. So `Option<extern "C" fn(c_int) -> c_int>` is a correct way
to represent a nullable function pointer using the C ABI (corresponding to the C type
`int (*)(int)`).

Here is a contrived example. Let's say some C library has a facility for registering a
callback, which gets called in certain situations. The callback is passed a function pointer
and an integer and it is supposed to run the function with the integer as a parameter. So
we have function pointers flying across the FFI boundary in both directions.

```rust
# #![feature(libc)]
extern crate libc;
use libc::c_int;

# #[cfg(hidden)]
extern "C" {
/// Register the callback.
fn register(cb: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>, c_int) -> c_int>);
}
# unsafe fn register(_: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>,
# c_int) -> c_int>)
# {}

/// This fairly useless function receives a function pointer and an integer
/// from C, and returns the result of calling the function with the integer.
/// In case no function is provided, it squares the integer by default.
extern "C" fn apply(process: Option<extern "C" fn(c_int) -> c_int>, int: c_int) -> c_int {
match process {
Some(f) => f(int),
None => int * int
}
}

fn main() {
unsafe {
register(Some(apply));
}
}
```

And the code on the C side looks like this:

```c
void register(void (*f)(void (*)(int), int)) {
...
}
```
No `transmute` required!
# Calling Rust code from C
Expand Down
20 changes: 7 additions & 13 deletions src/libcollections/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,37 +434,31 @@
//! in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part refers
//! to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
//!
//! For example, these:
//! For example, the following calls all print the same thing `Hello x is 0.01000`:
//!
//! ```
//! // Hello {arg 0 (x)} is {arg 1 (0.01) with precision specified inline (5)}
//! // Hello {arg 0 ("x")} is {arg 1 (0.01) with precision specified inline (5)}
//! println!("Hello {0} is {1:.5}", "x", 0.01);
//!
//! // Hello {arg 1 (x)} is {arg 2 (0.01) with precision specified in arg 0 (5)}
//! // Hello {arg 1 ("x")} is {arg 2 (0.01) with precision specified in arg 0 (5)}
//! println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
//!
//! // Hello {arg 0 (x)} is {arg 2 (0.01) with precision specified in arg 1 (5)}
//! // Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)}
//! println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
//!
//! // Hello {next arg (x)} is {second of next two args (0.01) with precision
//! // Hello {next arg ("x")} is {second of next two args (0.01) with precision
//! // specified in first of next two args (5)}
//! println!("Hello {} is {:.*}", "x", 5, 0.01);
//!
//! // Hello {next arg (x)} is {arg 2 (0.01) with precision
//! // Hello {next arg ("x")} is {arg 2 (0.01) with precision
//! // specified in its predecessor (5)}
//! println!("Hello {} is {2:.*}", "x", 5, 0.01);
//!
//! // Hello {next arg (x)} is {arg "number" (0.01) with precision specified
//! // Hello {next arg ("x")} is {arg "number" (0.01) with precision specified
//! // in arg "prec" (5)}
//! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
//! ```
//!
//! All print the same thing:
//!
//! ```text
//! Hello x is 0.01000
//! ```
//!
//! While these:
//!
//! ```
Expand Down
18 changes: 18 additions & 0 deletions src/libcore/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ macro_rules! panic {
/// This will invoke the `panic!` macro if the provided expression cannot be
/// evaluated to `true` at runtime.
///
/// Assertions are always checked in both debug and release builds, and cannot
/// be disabled. See `debug_assert!` for assertions that are not enabled in
/// release builds by default.
///
/// Unsafe code relies on `assert!` to enforce run-time invariants that, if
/// violated could lead to unsafety.
///
/// Other use-cases of `assert!` include
/// [testing](https://doc.rust-lang.org/book/testing.html) and enforcing
/// run-time invariants in safe code (whose violation cannot result in unsafety).
///
/// This macro has a second version, where a custom panic message can be provided.
///
/// # Examples
Expand Down Expand Up @@ -123,6 +134,13 @@ macro_rules! assert_eq {
/// expensive to be present in a release build but may be helpful during
/// development.
///
/// An unchecked assertion allows a program in an inconsistent state to keep
/// running, which might have unexpected consequences but does not introduce
/// unsafety as long as this only happens in safe code. The performance cost
/// of assertions, is however, not measurable in general. Replacing `assert!`
/// with `debug_assert!` is thus only encouraged after thorough profiling, and
/// more importantly, only in safe code!
///
/// # Examples
///
/// ```
Expand Down
13 changes: 13 additions & 0 deletions src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,19 @@ impl<'a> Chars<'a> {
///
/// This has the same lifetime as the original slice, and so the
/// iterator can continue to be used while this exists.
///
/// # Examples
///
/// ```
/// let mut chars = "abc".chars();
///
/// assert_eq!(chars.as_str(), "abc");
/// chars.next();
/// assert_eq!(chars.as_str(), "bc");
/// chars.next();
/// chars.next();
/// assert_eq!(chars.as_str(), "");
/// ```
#[stable(feature = "iter_to_slice", since = "1.4.0")]
#[inline]
pub fn as_str(&self) -> &'a str {
Expand Down
2 changes: 1 addition & 1 deletion src/libpanic_unwind/dwarf/eh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
}
}
}
// Ip is not present in the table. This should not hapen... but it does: issie #35011.
// Ip is not present in the table. This should not happen... but it does: issue #35011.
// So rather than returning EHAction::Terminate, we do this.
EHAction::None
} else {
Expand Down
51 changes: 51 additions & 0 deletions src/libstd/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,23 @@ impl Metadata {
///
/// This field may not be available on all platforms, and will return an
/// `Err` on platforms where it is not available.
///
/// # Examples
///
/// ```
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
/// let metadata = try!(fs::metadata("foo.txt"));
///
/// if let Ok(time) = metadata.modified() {
/// println!("{:?}", time);
/// } else {
/// println!("Not supported on this platform");
/// }
/// # Ok(())
/// # }
/// ```
#[stable(feature = "fs_time", since = "1.10.0")]
pub fn modified(&self) -> io::Result<SystemTime> {
self.0.modified().map(FromInner::from_inner)
Expand All @@ -712,6 +729,23 @@ impl Metadata {
///
/// This field may not be available on all platforms, and will return an
/// `Err` on platforms where it is not available.
///
/// # Examples
///
/// ```
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
/// let metadata = try!(fs::metadata("foo.txt"));
///
/// if let Ok(time) = metadata.accessed() {
/// println!("{:?}", time);
/// } else {
/// println!("Not supported on this platform");
/// }
/// # Ok(())
/// # }
/// ```
#[stable(feature = "fs_time", since = "1.10.0")]
pub fn accessed(&self) -> io::Result<SystemTime> {
self.0.accessed().map(FromInner::from_inner)
Expand All @@ -726,6 +760,23 @@ impl Metadata {
///
/// This field may not be available on all platforms, and will return an
/// `Err` on platforms where it is not available.
///
/// # Examples
///
/// ```
/// # fn foo() -> std::io::Result<()> {
/// use std::fs;
///
/// let metadata = try!(fs::metadata("foo.txt"));
///
/// if let Ok(time) = metadata.created() {
/// println!("{:?}", time);
/// } else {
/// println!("Not supported on this platform");
/// }
/// # Ok(())
/// # }
/// ```
#[stable(feature = "fs_time", since = "1.10.0")]
pub fn created(&self) -> io::Result<SystemTime> {
self.0.created().map(FromInner::from_inner)
Expand Down
50 changes: 50 additions & 0 deletions src/libstd/sys/unix/ext/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,53 @@ use sys::platform::fs::MetadataExt as UnixMetadataExt;
pub trait PermissionsExt {
/// Returns the underlying raw `mode_t` bits that are the standard Unix
/// permissions for this file.
///
/// # Examples
///
/// ```rust,ignore
/// use std::fs::File;
/// use std::os::unix::fs::PermissionsExt;
///
/// let f = try!(File::create("foo.txt"));
/// let metadata = try!(f.metadata());
/// let permissions = metadata.permissions();
///
/// println!("permissions: {}", permissions.mode());
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&self) -> u32;

/// Sets the underlying raw bits for this set of permissions.
///
/// # Examples
///
/// ```rust,ignore
/// use std::fs::File;
/// use std::os::unix::fs::PermissionsExt;
///
/// let f = try!(File::create("foo.txt"));
/// let metadata = try!(f.metadata());
/// let mut permissions = metadata.permissions();
///
/// permissions.set_mode(0o644); // Read/write for owner and read for others.
/// assert_eq!(permissions.mode(), 0o644);
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn set_mode(&mut self, mode: u32);

/// Creates a new instance of `Permissions` from the given set of Unix
/// permission bits.
///
/// # Examples
///
/// ```rust,ignore
/// use std::fs::Permissions;
/// use std::os::unix::fs::PermissionsExt;
///
/// // Read/write for owner and read for others.
/// let permissions = Permissions::from_mode(0o644);
/// assert_eq!(permissions.mode(), 0o644);
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn from_mode(mode: u32) -> Self;
}
Expand Down Expand Up @@ -63,6 +101,18 @@ pub trait OpenOptionsExt {
/// If no `mode` is set, the default of `0o666` will be used.
/// The operating system masks out bits with the systems `umask`, to produce
/// the final permissions.
///
/// # Examples
///
/// ```rust,ignore
/// extern crate libc;
/// use std::fs::OpenOptions;
/// use std::os::unix::fs::OpenOptionsExt;
///
/// let mut options = OpenOptions::new();
/// options.mode(0o644); // Give read/write for owner and read for others.
/// let file = options.open("foo.txt");
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&mut self, mode: u32) -> &mut Self;

Expand Down

0 comments on commit 5a7773a

Please sign in to comment.