Auto merge of #35100 - GuillaumeGomez:rollup, r=GuillaumeGomez
Rollup of 7 pull requests - Successful merges: #34258, #34894, #35050, #35062, #35066, #35072, #35087 - Failed merges:
This commit is contained in:
commit
5a7773a180
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
//!
|
||||
//! ```
|
||||
|
@ -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
|
||||
@ -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
|
||||
///
|
||||
/// ```
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
@ -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)
|
||||
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user