Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 7 pull requests #35100

Merged
merged 30 commits into from
Jul 29, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
14a7f4d
Fix #35031
Jul 26, 2016
ec8518e
Fix typos
vadimcn Jul 27, 2016
a727679
Update docs for assert! and debug_assert!
munyari Jul 27, 2016
032ea41
book/ffi: nullable pointer, libc cleanups
durka Jun 13, 2016
48ce206
generics-agnostic description
durka Jun 13, 2016
cc2fc48
expand nullable pointer example
durka Jun 13, 2016
84366b6
recursion
durka Jun 13, 2016
0016af5
not just a single field
durka Jun 13, 2016
1cceca8
foreign function interface interface
durka Jun 13, 2016
fae3335
extern fns require named parameters
durka Jun 14, 2016
5276b29
change confusing wording about discriminant
durka Jun 14, 2016
54ecc21
hack to make example compile
durka Jun 14, 2016
8e7abea
revert libc changes
durka Jul 27, 2016
1319b29
fix typo
durka Jul 27, 2016
29546dd
remove claim about searching through nested fields for the nullable t…
durka Jul 27, 2016
91acc39
Correct minor typo in debug_assert doc
munyari Jul 27, 2016
8760b1d
Revert section about panic! in assert! doc
munyari Jul 27, 2016
9a7367b
Mention debug_assert! in assert! doc
munyari Jul 27, 2016
52c50ba
Add doc examples for std::fs::Metadata
GuillaumeGomez Jul 28, 2016
8d3f20f
Add doc examples for std::fs::unix::OpenOptionsExt
GuillaumeGomez Jul 28, 2016
123bf1e
Add OpenOptionsExt doc examples
GuillaumeGomez Jul 28, 2016
f98c55d
Add documentation example for `str::Chars::as_str`.
frewsxcv Jul 27, 2016
3563e40
Try to clear up some awkward wording
brettcannon Jul 29, 2016
679f88d
Rollup merge of #34258 - durka:patch-25, r=steveklabnik
GuillaumeGomez Jul 29, 2016
72d1d06
Rollup merge of #35050 - knight42:improve-fmt-doc, r=steveklabnik
GuillaumeGomez Jul 29, 2016
41c8d3f
Rollup merge of #35062 - frewsxcv:chars-as-str, r=GuillaumeGomez
GuillaumeGomez Jul 29, 2016
01505a3
Rollup merge of #35066 - vadimcn:fix-typos, r=apasel422
GuillaumeGomez Jul 29, 2016
3f06bf9
Rollup merge of #35072 - munyari:assert_debug, r=steveklabnik
GuillaumeGomez Jul 29, 2016
d69161c
Rollup merge of #35087 - GuillaumeGomez:fs_docs, r=steveklabnik
GuillaumeGomez Jul 29, 2016
5f5fdf6
Rollup merge of #35103 - brettcannon:patch-1, r=Manishearth
GuillaumeGomez Jul 29, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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