Auto merge of #35053 - steveklabnik:rollup, r=steveklabnik
Rollup of 15 pull requests - Successful merges: #34461, #34609, #34732, #34850, #34935, #34974, #34990, #34995, #35001, #35009, #35010, #35019, #35028, #35029, #35043 - Failed merges:
This commit is contained in:
commit
edecc57cbf
@ -94,7 +94,7 @@
|
||||
* `|` (`|…| expr`): closures. See [Closures].
|
||||
* `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`).
|
||||
* `||` (`expr || expr`): logical or.
|
||||
* `_`: "ignored" pattern binding. See [Patterns (Ignoring bindings)].
|
||||
* `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]).
|
||||
|
||||
## Other Syntax
|
||||
|
||||
@ -231,6 +231,7 @@
|
||||
[Primitive Types (Tuples)]: primitive-types.html#tuples
|
||||
[Raw Pointers]: raw-pointers.html
|
||||
[Reference (Byte String Literals)]: ../reference.html#byte-string-literals
|
||||
[Reference (Integer literals)]: ../reference.html#integer-literals
|
||||
[Reference (Raw Byte String Literals)]: ../reference.html#raw-byte-string-literals
|
||||
[Reference (Raw String Literals)]: ../reference.html#raw-string-literals
|
||||
[References and Borrowing]: references-and-borrowing.html
|
||||
|
@ -123,7 +123,6 @@ dispatch with trait objects by casting:
|
||||
# trait Foo { fn method(&self) -> String; }
|
||||
# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } }
|
||||
# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } }
|
||||
|
||||
fn do_something(x: &Foo) {
|
||||
x.method();
|
||||
}
|
||||
@ -140,7 +139,6 @@ or by coercing:
|
||||
# trait Foo { fn method(&self) -> String; }
|
||||
# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } }
|
||||
# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } }
|
||||
|
||||
fn do_something(x: &Foo) {
|
||||
x.method();
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ struct Vec<T> {
|
||||
}
|
||||
```
|
||||
|
||||
Unlike the previous example it *appears* that everything is exactly as we
|
||||
Unlike the previous example, it *appears* that everything is exactly as we
|
||||
want. Every generic argument to Vec shows up in at least one field.
|
||||
Good to go!
|
||||
|
||||
@ -84,4 +84,3 @@ standard library made a utility for itself called `Unique<T>` which:
|
||||
* includes a `PhantomData<T>`
|
||||
* auto-derives Send/Sync as if T was contained
|
||||
* marks the pointer as NonZero for the null-pointer optimization
|
||||
|
||||
|
@ -1653,14 +1653,43 @@ the Rust ABI and the foreign ABI.
|
||||
A number of [attributes](#ffi-attributes) control the behavior of external blocks.
|
||||
|
||||
By default external blocks assume that the library they are calling uses the
|
||||
standard C "cdecl" ABI. Other ABIs may be specified using an `abi` string, as
|
||||
shown here:
|
||||
standard C ABI on the specific platform. Other ABIs may be specified using an
|
||||
`abi` string, as shown here:
|
||||
|
||||
```ignore
|
||||
// Interface to the Windows API
|
||||
extern "stdcall" { }
|
||||
```
|
||||
|
||||
There are three ABI strings which are cross-platform, and which all compilers
|
||||
are guaranteed to support:
|
||||
|
||||
* `extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any
|
||||
Rust code.
|
||||
* `extern "C"` -- This is the same as `extern fn foo()`; whatever the default
|
||||
your C compiler supports.
|
||||
* `extern "system"` -- Usually the same as `extern "C"`, except on Win32, in
|
||||
which case it's `"stdcall"`, or what you should use to link to the Windows API
|
||||
itself
|
||||
|
||||
There are also some platform-specific ABI strings:
|
||||
|
||||
* `extern "cdecl"` -- The default for x86\_32 C code.
|
||||
* `extern "stdcall"` -- The default for the Win32 API on x86\_32.
|
||||
* `extern "win64"` -- The default for C code on x86\_64 Windows.
|
||||
* `extern "aapcs"` -- The default for ARM.
|
||||
* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's
|
||||
`__fastcall` and GCC and clang's `__attribute__((fastcall))`
|
||||
* `extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's
|
||||
`__vectorcall` and clang's `__attribute__((vectorcall))`
|
||||
|
||||
Finally, there are some rustc-specific ABI strings:
|
||||
|
||||
* `extern "rust-intrinsic"` -- The ABI of rustc intrinsics.
|
||||
* `extern "rust-call"` -- The ABI of the Fn::call trait functions.
|
||||
* `extern "platform-intrinsic"` -- Specific platform intrinsics -- like, for
|
||||
example, `sqrt` -- have this ABI. You should never have to deal with it.
|
||||
|
||||
The `link` attribute allows the name of the library to be specified. When
|
||||
specified the compiler will attempt to link against the native library of the
|
||||
specified name.
|
||||
|
@ -691,15 +691,40 @@ impl<T> [T] {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Print the slice split by numbers divisible by 3 (i.e. `[10, 40]`,
|
||||
/// `[20]`, `[50]`):
|
||||
/// ```
|
||||
/// let slice = [10, 40, 33, 20];
|
||||
/// let mut iter = slice.split(|num| num % 3 == 0);
|
||||
///
|
||||
/// assert_eq!(iter.next().unwrap(), &[10, 40]);
|
||||
/// assert_eq!(iter.next().unwrap(), &[20]);
|
||||
/// assert!(iter.next().is_none());
|
||||
/// ```
|
||||
///
|
||||
/// If the first element is matched, an empty slice will be the first item
|
||||
/// returned by the iterator. Similarly, if the last element in the slice
|
||||
/// is matched, an empty slice will be the last item returned by the
|
||||
/// iterator:
|
||||
///
|
||||
/// ```
|
||||
/// let v = [10, 40, 30, 20, 60, 50];
|
||||
/// let slice = [10, 40, 33];
|
||||
/// let mut iter = slice.split(|num| num % 3 == 0);
|
||||
///
|
||||
/// for group in v.split(|num| *num % 3 == 0) {
|
||||
/// println!("{:?}", group);
|
||||
/// }
|
||||
/// assert_eq!(iter.next().unwrap(), &[10, 40]);
|
||||
/// assert_eq!(iter.next().unwrap(), &[]);
|
||||
/// assert!(iter.next().is_none());
|
||||
/// ```
|
||||
///
|
||||
/// If two matched elements are directly adjacent, an empty slice will be
|
||||
/// present between them:
|
||||
///
|
||||
/// ```
|
||||
/// let slice = [10, 6, 33, 20];
|
||||
/// let mut iter = slice.split(|num| num % 3 == 0);
|
||||
///
|
||||
/// assert_eq!(iter.next().unwrap(), &[10]);
|
||||
/// assert_eq!(iter.next().unwrap(), &[]);
|
||||
/// assert_eq!(iter.next().unwrap(), &[20]);
|
||||
/// assert!(iter.next().is_none());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
|
@ -402,6 +402,8 @@ impl<T> VecDeque<T> {
|
||||
|
||||
/// Retrieves an element in the `VecDeque` by index.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -425,6 +427,8 @@ impl<T> VecDeque<T> {
|
||||
|
||||
/// Retrieves an element in the `VecDeque` mutably by index.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -456,6 +460,8 @@ impl<T> VecDeque<T> {
|
||||
///
|
||||
/// Fails if there is no element with either index.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -1180,6 +1186,8 @@ impl<T> VecDeque<T> {
|
||||
///
|
||||
/// Returns `None` if `index` is out of bounds.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -1214,6 +1222,8 @@ impl<T> VecDeque<T> {
|
||||
///
|
||||
/// Returns `None` if `index` is out of bounds.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -1245,6 +1255,8 @@ impl<T> VecDeque<T> {
|
||||
/// end is closer to the insertion point will be moved to make room,
|
||||
/// and all the affected elements will be moved to new positions.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `index` is greater than `VecDeque`'s length
|
||||
@ -1472,6 +1484,8 @@ impl<T> VecDeque<T> {
|
||||
/// room, and all the affected elements will be moved to new positions.
|
||||
/// Returns `None` if `index` is out of bounds.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -1651,6 +1665,8 @@ impl<T> VecDeque<T> {
|
||||
///
|
||||
/// Note that the capacity of `self` does not change.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `at > len`
|
||||
|
@ -277,17 +277,200 @@ extern "rust-intrinsic" {
|
||||
/// Moves a value out of scope without running drop glue.
|
||||
pub fn forget<T>(_: T) -> ();
|
||||
|
||||
/// Unsafely transforms a value of one type into a value of another type.
|
||||
/// Reinterprets the bits of a value of one type as another type; both types
|
||||
/// must have the same size. Neither the original, nor the result, may be an
|
||||
/// [invalid value] (../../nomicon/meet-safe-and-unsafe.html).
|
||||
///
|
||||
/// Both types must have the same size.
|
||||
/// `transmute` is semantically equivalent to a bitwise move of one type
|
||||
/// into another. It copies the bits from the destination type into the
|
||||
/// source type, then forgets the original. It's equivalent to C's `memcpy`
|
||||
/// under the hood, just like `transmute_copy`.
|
||||
///
|
||||
/// `transmute` is incredibly unsafe. There are a vast number of ways to
|
||||
/// cause undefined behavior with this function. `transmute` should be
|
||||
/// the absolute last resort.
|
||||
///
|
||||
/// The [nomicon](../../nomicon/transmutes.html) has additional
|
||||
/// documentation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
/// There are a few things that `transmute` is really useful for.
|
||||
///
|
||||
/// let array: &[u8] = unsafe { mem::transmute("Rust") };
|
||||
/// assert_eq!(array, [82, 117, 115, 116]);
|
||||
/// Getting the bitpattern of a floating point type (or, more generally,
|
||||
/// type punning, when `T` and `U` aren't pointers):
|
||||
///
|
||||
/// ```
|
||||
/// let bitpattern = unsafe {
|
||||
/// std::mem::transmute::<f32, u32>(1.0)
|
||||
/// };
|
||||
/// assert_eq!(bitpattern, 0x3F800000);
|
||||
/// ```
|
||||
///
|
||||
/// Turning a pointer into a function pointer:
|
||||
///
|
||||
/// ```
|
||||
/// fn foo() -> i32 {
|
||||
/// 0
|
||||
/// }
|
||||
/// let pointer = foo as *const ();
|
||||
/// let function = unsafe {
|
||||
/// std::mem::transmute::<*const (), fn() -> i32>(pointer)
|
||||
/// };
|
||||
/// assert_eq!(function(), 0);
|
||||
/// ```
|
||||
///
|
||||
/// Extending a lifetime, or shortening an invariant lifetime; this is
|
||||
/// advanced, very unsafe rust:
|
||||
///
|
||||
/// ```
|
||||
/// struct R<'a>(&'a i32);
|
||||
/// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {
|
||||
/// std::mem::transmute::<R<'b>, R<'static>>(r)
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>)
|
||||
/// -> &'b mut R<'c> {
|
||||
/// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Alternatives
|
||||
///
|
||||
/// However, many uses of `transmute` can be achieved through other means.
|
||||
/// `transmute` can transform any type into any other, with just the caveat
|
||||
/// that they're the same size, and often interesting results occur. Below
|
||||
/// are common applications of `transmute` which can be replaced with safe
|
||||
/// applications of `as`:
|
||||
///
|
||||
/// Turning a pointer into a `usize`:
|
||||
///
|
||||
/// ```
|
||||
/// let ptr = &0;
|
||||
/// let ptr_num_transmute = unsafe {
|
||||
/// std::mem::transmute::<&i32, usize>(ptr)
|
||||
/// };
|
||||
/// // Use an `as` cast instead
|
||||
/// let ptr_num_cast = ptr as *const i32 as usize;
|
||||
/// ```
|
||||
///
|
||||
/// Turning a `*mut T` into an `&mut T`:
|
||||
///
|
||||
/// ```
|
||||
/// let ptr: *mut i32 = &mut 0;
|
||||
/// let ref_transmuted = unsafe {
|
||||
/// std::mem::transmute::<*mut i32, &mut i32>(ptr)
|
||||
/// };
|
||||
/// // Use a reborrow instead
|
||||
/// let ref_casted = unsafe { &mut *ptr };
|
||||
/// ```
|
||||
///
|
||||
/// Turning an `&mut T` into an `&mut U`:
|
||||
///
|
||||
/// ```
|
||||
/// let ptr = &mut 0;
|
||||
/// let val_transmuted = unsafe {
|
||||
/// std::mem::transmute::<&mut i32, &mut u32>(ptr)
|
||||
/// };
|
||||
/// // Now, put together `as` and reborrowing - note the chaining of `as`
|
||||
/// // `as` is not transitive
|
||||
/// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) };
|
||||
/// ```
|
||||
///
|
||||
/// Turning an `&str` into an `&[u8]`:
|
||||
///
|
||||
/// ```
|
||||
/// // this is not a good way to do this.
|
||||
/// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") };
|
||||
/// assert_eq!(slice, &[82, 117, 115, 116]);
|
||||
/// // You could use `str::as_bytes`
|
||||
/// let slice = "Rust".as_bytes();
|
||||
/// assert_eq!(slice, &[82, 117, 115, 116]);
|
||||
/// // Or, just use a byte string, if you have control over the string
|
||||
/// // literal
|
||||
/// assert_eq!(b"Rust", &[82, 117, 115, 116]);
|
||||
/// ```
|
||||
///
|
||||
/// Turning a `Vec<&T>` into a `Vec<Option<&T>>`:
|
||||
///
|
||||
/// ```
|
||||
/// let store = [0, 1, 2, 3];
|
||||
/// let mut v_orig = store.iter().collect::<Vec<&i32>>();
|
||||
/// // Using transmute: this is Undefined Behavior, and a bad idea.
|
||||
/// // However, it is no-copy.
|
||||
/// let v_transmuted = unsafe {
|
||||
/// std::mem::transmute::<Vec<&i32>, Vec<Option<&i32>>>(
|
||||
/// v_orig.clone())
|
||||
/// };
|
||||
/// // This is the suggested, safe way.
|
||||
/// // It does copy the entire Vector, though, into a new array.
|
||||
/// let v_collected = v_orig.clone()
|
||||
/// .into_iter()
|
||||
/// .map(|r| Some(r))
|
||||
/// .collect::<Vec<Option<&i32>>>();
|
||||
/// // The no-copy, unsafe way, still using transmute, but not UB.
|
||||
/// // This is equivalent to the original, but safer, and reuses the
|
||||
/// // same Vec internals. Therefore the new inner type must have the
|
||||
/// // exact same size, and the same or lesser alignment, as the old
|
||||
/// // type. The same caveats exist for this method as transmute, for
|
||||
/// // the original inner type (`&i32`) to the converted inner type
|
||||
/// // (`Option<&i32>`), so read the nomicon pages linked above.
|
||||
/// let v_from_raw = unsafe {
|
||||
/// Vec::from_raw_parts(v_orig.as_mut_ptr(),
|
||||
/// v_orig.len(),
|
||||
/// v_orig.capacity())
|
||||
/// };
|
||||
/// std::mem::forget(v_orig);
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `split_at_mut`:
|
||||
///
|
||||
/// ```
|
||||
/// use std::{slice, mem};
|
||||
/// // There are multiple ways to do this; and there are multiple problems
|
||||
/// // with the following, transmute, way.
|
||||
/// fn split_at_mut_transmute<T>(slice: &mut [T], mid: usize)
|
||||
/// -> (&mut [T], &mut [T]) {
|
||||
/// let len = slice.len();
|
||||
/// assert!(mid <= len);
|
||||
/// unsafe {
|
||||
/// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice);
|
||||
/// // first: transmute is not typesafe; all it checks is that T and
|
||||
/// // U are of the same size. Second, right here, you have two
|
||||
/// // mutable references pointing to the same memory.
|
||||
/// (&mut slice[0..mid], &mut slice2[mid..len])
|
||||
/// }
|
||||
/// }
|
||||
/// // This gets rid of the typesafety problems; `&mut *` will *only* give
|
||||
/// // you an `&mut T` from an `&mut T` or `*mut T`.
|
||||
/// fn split_at_mut_casts<T>(slice: &mut [T], mid: usize)
|
||||
/// -> (&mut [T], &mut [T]) {
|
||||
/// let len = slice.len();
|
||||
/// assert!(mid <= len);
|
||||
/// unsafe {
|
||||
/// let slice2 = &mut *(slice as *mut [T]);
|
||||
/// // however, you still have two mutable references pointing to
|
||||
/// // the same memory.
|
||||
/// (&mut slice[0..mid], &mut slice2[mid..len])
|
||||
/// }
|
||||
/// }
|
||||
/// // This is how the standard library does it. This is the best method, if
|
||||
/// // you need to do something like this
|
||||
/// fn split_at_stdlib<T>(slice: &mut [T], mid: usize)
|
||||
/// -> (&mut [T], &mut [T]) {
|
||||
/// let len = slice.len();
|
||||
/// assert!(mid <= len);
|
||||
/// unsafe {
|
||||
/// let ptr = slice.as_mut_ptr();
|
||||
/// // This now has three mutable references pointing at the same
|
||||
/// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1.
|
||||
/// // `slice` is never used after `let ptr = ...`, and so one can
|
||||
/// // treat it as "dead", and therefore, you only have two real
|
||||
/// // mutable slices.
|
||||
/// (slice::from_raw_parts_mut(ptr, mid),
|
||||
/// slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn transmute<T, U>(e: T) -> U;
|
||||
|
@ -386,10 +386,11 @@ pub trait Extend<A> {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait DoubleEndedIterator: Iterator {
|
||||
/// An iterator able to yield elements from both ends.
|
||||
/// Removes and returns an element from the end of the iterator.
|
||||
///
|
||||
/// As this is the only method for this trait, the [trait-level] docs
|
||||
/// contain more details.
|
||||
/// Returns `None` when there are no more elements.
|
||||
///
|
||||
/// The [trait-level] docs contain more details.
|
||||
///
|
||||
/// [trait-level]: trait.DoubleEndedIterator.html
|
||||
///
|
||||
|
@ -427,7 +427,7 @@ fn make_values_str(pairs: &[(&'static str, &str)]) -> String {
|
||||
}
|
||||
|
||||
fn span_extent_str(span: SpanData) -> String {
|
||||
format!("file_name,\"{}\",file_line,{},file_col,{},byte_start,{}\
|
||||
format!("file_name,\"{}\",file_line,{},file_col,{},byte_start,{},\
|
||||
file_line_end,{},file_col_end,{},byte_end,{}",
|
||||
span.file_name, span.line_start, span.column_start, span.byte_start,
|
||||
span.line_end, span.column_end, span.byte_end)
|
||||
|
@ -877,7 +877,7 @@ impl<K, V, S> HashMap<K, V, S>
|
||||
/// }
|
||||
///
|
||||
/// for val in map.values() {
|
||||
/// print!("{}", val);
|
||||
/// println!("{}", val);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "map_values_mut", since = "1.10.0")]
|
||||
@ -1336,6 +1336,10 @@ impl<'a, K, V> InternalEntry<K, V, &'a mut RawTable<K, V>> {
|
||||
}
|
||||
|
||||
/// A view into a single location in a map, which may be vacant or occupied.
|
||||
/// This enum is constructed from the [`entry`] method on [`HashMap`].
|
||||
///
|
||||
/// [`HashMap`]: struct.HashMap.html
|
||||
/// [`entry`]: struct.HashMap.html#method.entry
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub enum Entry<'a, K: 'a, V: 'a> {
|
||||
/// An occupied Entry.
|
||||
@ -1366,6 +1370,9 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> {
|
||||
}
|
||||
|
||||
/// A view into a single occupied location in a HashMap.
|
||||
/// It is part of the [`Entry`] enum.
|
||||
///
|
||||
/// [`Entry`]: enum.Entry.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
|
||||
key: Option<K>,
|
||||
@ -1383,6 +1390,9 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> {
|
||||
}
|
||||
|
||||
/// A view into a single empty location in a HashMap.
|
||||
/// It is part of the [`Entry`] enum.
|
||||
///
|
||||
/// [`Entry`]: enum.Entry.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct VacantEntry<'a, K: 'a, V: 'a> {
|
||||
hash: SafeHash,
|
||||
@ -1551,6 +1561,20 @@ impl<'a, K, V> Entry<'a, K, V> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
/// Ensures a value is in the entry by inserting the default if empty, and returns
|
||||
/// a mutable reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 12);
|
||||
///
|
||||
/// *map.entry("poneyland").or_insert(12) += 10;
|
||||
/// assert_eq!(map["poneyland"], 22);
|
||||
/// ```
|
||||
pub fn or_insert(self, default: V) -> &'a mut V {
|
||||
match self {
|
||||
Occupied(entry) => entry.into_mut(),
|
||||
@ -1561,6 +1585,19 @@ impl<'a, K, V> Entry<'a, K, V> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
/// Ensures a value is in the entry by inserting the result of the default function if empty,
|
||||
/// and returns a mutable reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, String> = HashMap::new();
|
||||
/// let s = "hoho".to_owned();
|
||||
///
|
||||
/// map.entry("poneyland").or_insert_with(|| s);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], "hoho".to_owned());
|
||||
/// ```
|
||||
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
|
||||
match self {
|
||||
Occupied(entry) => entry.into_mut(),
|
||||
@ -1569,6 +1606,15 @@ impl<'a, K, V> Entry<'a, K, V> {
|
||||
}
|
||||
|
||||
/// Returns a reference to this entry's key.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// assert_eq!(map.entry("poneyland").key(), &"poneyland");
|
||||
/// ```
|
||||
#[stable(feature = "map_entry_keys", since = "1.10.0")]
|
||||
pub fn key(&self) -> &K {
|
||||
match *self {
|
||||
@ -1580,37 +1626,130 @@ impl<'a, K, V> Entry<'a, K, V> {
|
||||
|
||||
impl<'a, K, V> OccupiedEntry<'a, K, V> {
|
||||
/// Gets a reference to the key in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
/// assert_eq!(map.entry("poneyland").key(), &"poneyland");
|
||||
/// ```
|
||||
#[stable(feature = "map_entry_keys", since = "1.10.0")]
|
||||
pub fn key(&self) -> &K {
|
||||
self.elem.read().0
|
||||
}
|
||||
|
||||
/// Take the ownership of the key and value from the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_entry_recover_keys)]
|
||||
///
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::collections::hash_map::Entry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let Entry::Occupied(o) = map.entry("poneyland") {
|
||||
/// // We delete the entry from the map.
|
||||
/// o.remove_pair();
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(map.contains_key("poneyland"), false);
|
||||
/// ```
|
||||
#[unstable(feature = "map_entry_recover_keys", issue = "34285")]
|
||||
pub fn remove_pair(self) -> (K, V) {
|
||||
pop_internal(self.elem)
|
||||
}
|
||||
|
||||
/// Gets a reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::collections::hash_map::Entry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let Entry::Occupied(o) = map.entry("poneyland") {
|
||||
/// assert_eq!(o.get(), &12);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get(&self) -> &V {
|
||||
self.elem.read().1
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::collections::hash_map::Entry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 12);
|
||||
/// if let Entry::Occupied(mut o) = map.entry("poneyland") {
|
||||
/// *o.get_mut() += 10;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 22);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get_mut(&mut self) -> &mut V {
|
||||
self.elem.read_mut().1
|
||||
}
|
||||
|
||||
/// Converts the OccupiedEntry into a mutable reference to the value in the entry
|
||||
/// with a lifetime bound to the map itself
|
||||
/// with a lifetime bound to the map itself.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::collections::hash_map::Entry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 12);
|
||||
/// if let Entry::Occupied(o) = map.entry("poneyland") {
|
||||
/// *o.into_mut() += 10;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 22);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn into_mut(self) -> &'a mut V {
|
||||
self.elem.into_mut_refs().1
|
||||
}
|
||||
|
||||
/// Sets the value of the entry, and returns the entry's old value
|
||||
/// Sets the value of the entry, and returns the entry's old value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::collections::hash_map::Entry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let Entry::Occupied(mut o) = map.entry("poneyland") {
|
||||
/// assert_eq!(o.insert(15), 12);
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 15);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn insert(&mut self, mut value: V) -> V {
|
||||
let old_value = self.get_mut();
|
||||
@ -1618,7 +1757,23 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
|
||||
value
|
||||
}
|
||||
|
||||
/// Takes the value out of the entry, and returns it
|
||||
/// Takes the value out of the entry, and returns it.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::collections::hash_map::Entry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let Entry::Occupied(o) = map.entry("poneyland") {
|
||||
/// assert_eq!(o.remove(), 12);
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(map.contains_key("poneyland"), false);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn remove(self) -> V {
|
||||
pop_internal(self.elem).1
|
||||
@ -1634,20 +1789,58 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
|
||||
|
||||
impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
|
||||
/// Gets a reference to the key that would be used when inserting a value
|
||||
/// through the VacantEntry.
|
||||
/// through the `VacantEntry`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// assert_eq!(map.entry("poneyland").key(), &"poneyland");
|
||||
/// ```
|
||||
#[stable(feature = "map_entry_keys", since = "1.10.0")]
|
||||
pub fn key(&self) -> &K {
|
||||
&self.key
|
||||
}
|
||||
|
||||
/// Take ownership of the key.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_entry_recover_keys)]
|
||||
///
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::collections::hash_map::Entry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
///
|
||||
/// if let Entry::Vacant(v) = map.entry("poneyland") {
|
||||
/// v.into_key();
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "map_entry_recover_keys", issue = "34285")]
|
||||
pub fn into_key(self) -> K {
|
||||
self.key
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the VacantEntry's key,
|
||||
/// and returns a mutable reference to it
|
||||
/// and returns a mutable reference to it.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
/// use std::collections::hash_map::Entry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
///
|
||||
/// if let Entry::Vacant(o) = map.entry("poneyland") {
|
||||
/// o.insert(37);
|
||||
/// }
|
||||
/// assert_eq!(map["poneyland"], 37);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn insert(self, value: V) -> &'a mut V {
|
||||
match self.elem {
|
||||
|
143
src/libstd/fs.rs
143
src/libstd/fs.rs
@ -58,28 +58,37 @@ pub struct File {
|
||||
|
||||
/// Metadata information about a file.
|
||||
///
|
||||
/// This structure is returned from the `metadata` function or method and
|
||||
/// This structure is returned from the [`metadata`] function or method and
|
||||
/// represents known metadata about a file such as its permissions, size,
|
||||
/// modification times, etc.
|
||||
///
|
||||
/// [`metadata`]: fn.metadata.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(Clone)]
|
||||
pub struct Metadata(fs_imp::FileAttr);
|
||||
|
||||
/// Iterator over the entries in a directory.
|
||||
///
|
||||
/// This iterator is returned from the `read_dir` function of this module and
|
||||
/// will yield instances of `io::Result<DirEntry>`. Through a `DirEntry`
|
||||
/// This iterator is returned from the [`read_dir`] function of this module and
|
||||
/// will yield instances of `io::Result<DirEntry>`. Through a [`DirEntry`]
|
||||
/// information like the entry's path and possibly other metadata can be
|
||||
/// learned.
|
||||
///
|
||||
/// [`read_dir`]: fn.read_dir.html
|
||||
/// [`DirEntry`]: struct.DirEntry.html
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This `io::Result` will be an `Err` if there's some sort of intermittent
|
||||
/// This [`io::Result`] will be an `Err` if there's some sort of intermittent
|
||||
/// IO error during iteration.
|
||||
///
|
||||
/// [`io::Result`]: ../io/type.Result.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct ReadDir(fs_imp::ReadDir);
|
||||
|
||||
/// Entries returned by the `ReadDir` iterator.
|
||||
/// Entries returned by the [`ReadDir`] iterator.
|
||||
///
|
||||
/// [`ReadDir`]: struct.ReadDir.html
|
||||
///
|
||||
/// An instance of `DirEntry` represents an entry inside of a directory on the
|
||||
/// filesystem. Each entry can be inspected via methods to learn about the full
|
||||
@ -89,17 +98,23 @@ pub struct DirEntry(fs_imp::DirEntry);
|
||||
|
||||
/// Options and flags which can be used to configure how a file is opened.
|
||||
///
|
||||
/// This builder exposes the ability to configure how a `File` is opened and
|
||||
/// what operations are permitted on the open file. The `File::open` and
|
||||
/// `File::create` methods are aliases for commonly used options using this
|
||||
/// This builder exposes the ability to configure how a [`File`] is opened and
|
||||
/// what operations are permitted on the open file. The [`File::open`] and
|
||||
/// [`File::create`] methods are aliases for commonly used options using this
|
||||
/// builder.
|
||||
///
|
||||
/// Generally speaking, when using `OpenOptions`, you'll first call `new()`,
|
||||
/// then chain calls to methods to set each option, then call `open()`, passing
|
||||
/// the path of the file you're trying to open. This will give you a
|
||||
/// [`File`]: struct.File.html
|
||||
/// [`File::open`]: struct.File.html#method.open
|
||||
/// [`File::create`]: struct.File.html#method.create
|
||||
///
|
||||
/// Generally speaking, when using `OpenOptions`, you'll first call [`new()`],
|
||||
/// then chain calls to methods to set each option, then call [`open()`],
|
||||
/// passing the path of the file you're trying to open. This will give you a
|
||||
/// [`io::Result`][result] with a [`File`][file] inside that you can further
|
||||
/// operate on.
|
||||
///
|
||||
/// [`new()`]: struct.OpenOptions.html#method.new
|
||||
/// [`open()`]: struct.OpenOptions.html#method.open
|
||||
/// [result]: ../io/type.Result.html
|
||||
/// [file]: struct.File.html
|
||||
///
|
||||
@ -131,10 +146,12 @@ pub struct OpenOptions(fs_imp::OpenOptions);
|
||||
|
||||
/// Representation of the various permissions on a file.
|
||||
///
|
||||
/// This module only currently provides one bit of information, `readonly`,
|
||||
/// This module only currently provides one bit of information, [`readonly`],
|
||||
/// which is exposed on all currently supported platforms. Unix-specific
|
||||
/// functionality, such as mode bits, is available through the
|
||||
/// `os::unix::PermissionsExt` trait.
|
||||
///
|
||||
/// [`readonly`]: struct.Permissions.html#method.readonly
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Permissions(fs_imp::FilePermissions);
|
||||
@ -156,12 +173,14 @@ pub struct DirBuilder {
|
||||
impl File {
|
||||
/// Attempts to open a file in read-only mode.
|
||||
///
|
||||
/// See the `OpenOptions::open` method for more details.
|
||||
/// See the [`OpenOptions::open`] method for more details.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if `path` does not already exist.
|
||||
/// Other errors may also be returned according to `OpenOptions::open`.
|
||||
/// Other errors may also be returned according to [`OpenOptions::open`].
|
||||
///
|
||||
/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -183,7 +202,9 @@ impl File {
|
||||
/// This function will create a file if it does not exist,
|
||||
/// and will truncate it if it does.
|
||||
///
|
||||
/// See the `OpenOptions::open` function for more details.
|
||||
/// See the [`OpenOptions::open`] function for more details.
|
||||
///
|
||||
/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -224,7 +245,7 @@ impl File {
|
||||
self.inner.fsync()
|
||||
}
|
||||
|
||||
/// This function is similar to `sync_all`, except that it may not
|
||||
/// This function is similar to [`sync_all`], except that it may not
|
||||
/// synchronize file metadata to the filesystem.
|
||||
///
|
||||
/// This is intended for use cases that must synchronize content, but don't
|
||||
@ -232,7 +253,9 @@ impl File {
|
||||
/// operations.
|
||||
///
|
||||
/// Note that some platforms may simply implement this in terms of
|
||||
/// `sync_all`.
|
||||
/// [`sync_all`].
|
||||
///
|
||||
/// [`sync_all`]: struct.File.html#method.sync_all
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -304,6 +327,18 @@ impl File {
|
||||
/// The returned `File` is a reference to the same state that this object
|
||||
/// references. Both handles will read and write with the same cursor
|
||||
/// position.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
///
|
||||
/// # fn foo() -> std::io::Result<()> {
|
||||
/// let mut f = try!(File::open("foo.txt"));
|
||||
/// let file_copy = try!(f.try_clone());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[stable(feature = "file_try_clone", since = "1.9.0")]
|
||||
pub fn try_clone(&self) -> io::Result<File> {
|
||||
Ok(File {
|
||||
@ -829,6 +864,26 @@ impl DirEntry {
|
||||
/// On Windows this function is cheap to call (no extra system calls
|
||||
/// needed), but on Unix platforms this function is the equivalent of
|
||||
/// calling `symlink_metadata` on the path.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::fs;
|
||||
///
|
||||
/// if let Ok(entries) = fs::read_dir(".") {
|
||||
/// for entry in entries {
|
||||
/// if let Ok(entry) = entry {
|
||||
/// // Here, `entry` is a `DirEntry`.
|
||||
/// if let Ok(metadata) = entry.metadata() {
|
||||
/// // Now let's show our entry's permissions!
|
||||
/// println!("{:?}: {:?}", entry.path(), metadata.permissions());
|
||||
/// } else {
|
||||
/// println!("Couldn't get metadata for {:?}", entry.path());
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
|
||||
pub fn metadata(&self) -> io::Result<Metadata> {
|
||||
self.0.metadata().map(Metadata)
|
||||
@ -844,6 +899,26 @@ impl DirEntry {
|
||||
/// On Windows and most Unix platforms this function is free (no extra
|
||||
/// system calls needed), but some Unix platforms may require the equivalent
|
||||
/// call to `symlink_metadata` to learn about the target file type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::fs;
|
||||
///
|
||||
/// if let Ok(entries) = fs::read_dir(".") {
|
||||
/// for entry in entries {
|
||||
/// if let Ok(entry) = entry {
|
||||
/// // Here, `entry` is a `DirEntry`.
|
||||
/// if let Ok(file_type) = entry.file_type() {
|
||||
/// // Now let's show our entry's file type!
|
||||
/// println!("{:?}: {:?}", entry.path(), file_type);
|
||||
/// } else {
|
||||
/// println!("Couldn't get file type for {:?}", entry.path());
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
|
||||
pub fn file_type(&self) -> io::Result<FileType> {
|
||||
self.0.file_type().map(FileType)
|
||||
@ -851,6 +926,21 @@ impl DirEntry {
|
||||
|
||||
/// Returns the bare file name of this directory entry without any other
|
||||
/// leading path component.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::fs;
|
||||
///
|
||||
/// if let Ok(entries) = fs::read_dir(".") {
|
||||
/// for entry in entries {
|
||||
/// if let Ok(entry) = entry {
|
||||
/// // Here, `entry` is a `DirEntry`.
|
||||
/// println!("{:?}", entry.file_name());
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
|
||||
pub fn file_name(&self) -> OsString {
|
||||
self.0.file_name()
|
||||
@ -1397,6 +1487,14 @@ pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions)
|
||||
impl DirBuilder {
|
||||
/// Creates a new set of options with default mode/security settings for all
|
||||
/// platforms and also non-recursive.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::fs::DirBuilder;
|
||||
///
|
||||
/// let builder = DirBuilder::new();
|
||||
/// ```
|
||||
#[stable(feature = "dir_builder", since = "1.6.0")]
|
||||
pub fn new() -> DirBuilder {
|
||||
DirBuilder {
|
||||
@ -1409,7 +1507,16 @@ impl DirBuilder {
|
||||
/// all parent directories if they do not exist with the same security and
|
||||
/// permissions settings.
|
||||
///
|
||||
/// This option defaults to `false`
|
||||
/// This option defaults to `false`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::fs::DirBuilder;
|
||||
///
|
||||
/// let mut builder = DirBuilder::new();
|
||||
/// builder.recursive(true);
|
||||
/// ```
|
||||
#[stable(feature = "dir_builder", since = "1.6.0")]
|
||||
pub fn recursive(&mut self, recursive: bool) -> &mut Self {
|
||||
self.recursive = recursive;
|
||||
|
@ -196,6 +196,22 @@ impl FileTypeExt for fs::FileType {
|
||||
pub trait DirEntryExt {
|
||||
/// Returns the underlying `d_ino` field in the contained `dirent`
|
||||
/// structure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::fs;
|
||||
/// use std::os::unix::fs::DirEntryExt;
|
||||
///
|
||||
/// if let Ok(entries) = fs::read_dir(".") {
|
||||
/// for entry in entries {
|
||||
/// if let Ok(entry) = entry {
|
||||
/// // Here, `entry` is a `DirEntry`.
|
||||
/// println!("{:?}: {}", entry.file_name(), entry.ino());
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
|
||||
fn ino(&self) -> u64;
|
||||
}
|
||||
@ -239,6 +255,16 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
|
||||
pub trait DirBuilderExt {
|
||||
/// Sets the mode to create new directories with. This option defaults to
|
||||
/// 0o777.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use std::fs::DirBuilder;
|
||||
/// use std::os::unix::fs::DirBuilderExt;
|
||||
///
|
||||
/// let mut builder = DirBuilder::new();
|
||||
/// builder.mode(0o755);
|
||||
/// ```
|
||||
#[stable(feature = "dir_builder", since = "1.6.0")]
|
||||
fn mode(&mut self, mode: u32) -> &mut Self;
|
||||
}
|
||||
|
@ -1,369 +0,0 @@
|
||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// 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-android: FIXME(#10381)
|
||||
// min-lldb-version: 310
|
||||
|
||||
// This test case checks if function arguments already have the correct value
|
||||
// when breaking at the beginning of a function. Functions with the
|
||||
// #[no_stack_check] attribute have the same prologue as regular C functions
|
||||
// compiled with GCC or Clang and therefore are better handled by GDB. As a
|
||||
// consequence, and as opposed to regular Rust functions, we can set the
|
||||
// breakpoints via the function name (and don't have to fall back on using line
|
||||
// numbers). For LLDB this shouldn't make a difference because it can handle
|
||||
// both cases.
|
||||
|
||||
// compile-flags:-g
|
||||
|
||||
// === GDB TESTS ===================================================================================
|
||||
|
||||
// gdb-command:rbreak immediate_args
|
||||
// gdb-command:rbreak binding
|
||||
// gdb-command:rbreak assignment
|
||||
// gdb-command:rbreak function_call
|
||||
// gdb-command:rbreak identifier
|
||||
// gdb-command:rbreak return_expr
|
||||
// gdb-command:rbreak arithmetic_expr
|
||||
// gdb-command:rbreak if_expr
|
||||
// gdb-command:rbreak while_expr
|
||||
// gdb-command:rbreak loop_expr
|
||||
// gdb-command:run
|
||||
|
||||
// IMMEDIATE ARGS
|
||||
// gdb-command:print a
|
||||
// gdb-check:$1 = 1
|
||||
// gdb-command:print b
|
||||
// gdb-check:$2 = true
|
||||
// gdb-command:print c
|
||||
// gdb-check:$3 = 2.5
|
||||
// gdb-command:continue
|
||||
|
||||
// NON IMMEDIATE ARGS
|
||||
// gdb-command:print a
|
||||
// gdb-check:$4 = {a = 3, b = 4, c = 5, d = 6, e = 7, f = 8, g = 9, h = 10}
|
||||
// gdb-command:print b
|
||||
// gdb-check:$5 = {a = 11, b = 12, c = 13, d = 14, e = 15, f = 16, g = 17, h = 18}
|
||||
// gdb-command:continue
|
||||
|
||||
// BINDING
|
||||
// gdb-command:print a
|
||||
// gdb-check:$6 = 19
|
||||
// gdb-command:print b
|
||||
// gdb-check:$7 = 20
|
||||
// gdb-command:print c
|
||||
// gdb-check:$8 = 21.5
|
||||
// gdb-command:continue
|
||||
|
||||
// ASSIGNMENT
|
||||
// gdb-command:print a
|
||||
// gdb-check:$9 = 22
|
||||
// gdb-command:print b
|
||||
// gdb-check:$10 = 23
|
||||
// gdb-command:print c
|
||||
// gdb-check:$11 = 24.5
|
||||
// gdb-command:continue
|
||||
|
||||
// FUNCTION CALL
|
||||
// gdb-command:print x
|
||||
// gdb-check:$12 = 25
|
||||
// gdb-command:print y
|
||||
// gdb-check:$13 = 26
|
||||
// gdb-command:print z
|
||||
// gdb-check:$14 = 27.5
|
||||
// gdb-command:continue
|
||||
|
||||
// EXPR
|
||||
// gdb-command:print x
|
||||
// gdb-check:$15 = 28
|
||||
// gdb-command:print y
|
||||
// gdb-check:$16 = 29
|
||||
// gdb-command:print z
|
||||
// gdb-check:$17 = 30.5
|
||||
// gdb-command:continue
|
||||
|
||||
// RETURN EXPR
|
||||
// gdb-command:print x
|
||||
// gdb-check:$18 = 31
|
||||
// gdb-command:print y
|
||||
// gdb-check:$19 = 32
|
||||
// gdb-command:print z
|
||||
// gdb-check:$20 = 33.5
|
||||
// gdb-command:continue
|
||||
|
||||
// ARITHMETIC EXPR
|
||||
// gdb-command:print x
|
||||
// gdb-check:$21 = 34
|
||||
// gdb-command:print y
|
||||
// gdb-check:$22 = 35
|
||||
// gdb-command:print z
|
||||
// gdb-check:$23 = 36.5
|
||||
// gdb-command:continue
|
||||
|
||||
// IF EXPR
|
||||
// gdb-command:print x
|
||||
// gdb-check:$24 = 37
|
||||
// gdb-command:print y
|
||||
// gdb-check:$25 = 38
|
||||
// gdb-command:print z
|
||||
// gdb-check:$26 = 39.5
|
||||
// gdb-command:continue
|
||||
|
||||
// WHILE EXPR
|
||||
// gdb-command:print x
|
||||
// gdb-check:$27 = 40
|
||||
// gdb-command:print y
|
||||
// gdb-check:$28 = 41
|
||||
// gdb-command:print z
|
||||
// gdb-check:$29 = 42
|
||||
// gdb-command:continue
|
||||
|
||||
// LOOP EXPR
|
||||
// gdb-command:print x
|
||||
// gdb-check:$30 = 43
|
||||
// gdb-command:print y
|
||||
// gdb-check:$31 = 44
|
||||
// gdb-command:print z
|
||||
// gdb-check:$32 = 45
|
||||
// gdb-command:continue
|
||||
|
||||
|
||||
// === LLDB TESTS ==================================================================================
|
||||
|
||||
// lldb-command:breakpoint set --name immediate_args
|
||||
// lldb-command:breakpoint set --name non_immediate_args
|
||||
// lldb-command:breakpoint set --name binding
|
||||
// lldb-command:breakpoint set --name assignment
|
||||
// lldb-command:breakpoint set --name function_call
|
||||
// lldb-command:breakpoint set --name identifier
|
||||
// lldb-command:breakpoint set --name return_expr
|
||||
// lldb-command:breakpoint set --name arithmetic_expr
|
||||
// lldb-command:breakpoint set --name if_expr
|
||||
// lldb-command:breakpoint set --name while_expr
|
||||
// lldb-command:breakpoint set --name loop_expr
|
||||
// lldb-command:run
|
||||
|
||||
// IMMEDIATE ARGS
|
||||
// lldb-command:print a
|
||||
// lldb-check:[...]$0 = 1
|
||||
// lldb-command:print b
|
||||
// lldb-check:[...]$1 = true
|
||||
// lldb-command:print c
|
||||
// lldb-check:[...]$2 = 2.5
|
||||
// lldb-command:continue
|
||||
|
||||
// NON IMMEDIATE ARGS
|
||||
// lldb-command:print a
|
||||
// lldb-check:[...]$3 = BigStruct { a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10 }
|
||||
// lldb-command:print b
|
||||
// lldb-check:[...]$4 = BigStruct { a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18 }
|
||||
// lldb-command:continue
|
||||
|
||||
// BINDING
|
||||
// lldb-command:print a
|
||||
// lldb-check:[...]$5 = 19
|
||||
// lldb-command:print b
|
||||
// lldb-check:[...]$6 = 20
|
||||
// lldb-command:print c
|
||||
// lldb-check:[...]$7 = 21.5
|
||||
// lldb-command:continue
|
||||
|
||||
// ASSIGNMENT
|
||||
// lldb-command:print a
|
||||
// lldb-check:[...]$8 = 22
|
||||
// lldb-command:print b
|
||||
// lldb-check:[...]$9 = 23
|
||||
// lldb-command:print c
|
||||
// lldb-check:[...]$10 = 24.5
|
||||
// lldb-command:continue
|
||||
|
||||
// FUNCTION CALL
|
||||
// lldb-command:print x
|
||||
// lldb-check:[...]$11 = 25
|
||||
// lldb-command:print y
|
||||
// lldb-check:[...]$12 = 26
|
||||
// lldb-command:print z
|
||||
// lldb-check:[...]$13 = 27.5
|
||||
// lldb-command:continue
|
||||
|
||||
// EXPR
|
||||
// lldb-command:print x
|
||||
// lldb-check:[...]$14 = 28
|
||||
// lldb-command:print y
|
||||
// lldb-check:[...]$15 = 29
|
||||
// lldb-command:print z
|
||||
// lldb-check:[...]$16 = 30.5
|
||||
// lldb-command:continue
|
||||
|
||||
// RETURN EXPR
|
||||
// lldb-command:print x
|
||||
// lldb-check:[...]$17 = 31
|
||||
// lldb-command:print y
|
||||
// lldb-check:[...]$18 = 32
|
||||
// lldb-command:print z
|
||||
// lldb-check:[...]$19 = 33.5
|
||||
// lldb-command:continue
|
||||
|
||||
// ARITHMETIC EXPR
|
||||
// lldb-command:print x
|
||||
// lldb-check:[...]$20 = 34
|
||||
// lldb-command:print y
|
||||
// lldb-check:[...]$21 = 35
|
||||
// lldb-command:print z
|
||||
// lldb-check:[...]$22 = 36.5
|
||||
// lldb-command:continue
|
||||
|
||||
// IF EXPR
|
||||
// lldb-command:print x
|
||||
// lldb-check:[...]$23 = 37
|
||||
// lldb-command:print y
|
||||
// lldb-check:[...]$24 = 38
|
||||
// lldb-command:print z
|
||||
// lldb-check:[...]$25 = 39.5
|
||||
// lldb-command:continue
|
||||
|
||||
// WHILE EXPR
|
||||
// lldb-command:print x
|
||||
// lldb-check:[...]$26 = 40
|
||||
// lldb-command:print y
|
||||
// lldb-check:[...]$27 = 41
|
||||
// lldb-command:print z
|
||||
// lldb-check:[...]$28 = 42
|
||||
// lldb-command:continue
|
||||
|
||||
// LOOP EXPR
|
||||
// lldb-command:print x
|
||||
// lldb-check:[...]$29 = 43
|
||||
// lldb-command:print y
|
||||
// lldb-check:[...]$30 = 44
|
||||
// lldb-command:print z
|
||||
// lldb-check:[...]$31 = 45
|
||||
// lldb-command:continue
|
||||
|
||||
#![allow(dead_code, unused_assignments, unused_variables)]
|
||||
#![feature(omit_gdb_pretty_printer_section)]
|
||||
#![omit_gdb_pretty_printer_section]
|
||||
|
||||
#[no_stack_check]
|
||||
fn immediate_args(a: isize, b: bool, c: f64) {
|
||||
println!("");
|
||||
}
|
||||
|
||||
struct BigStruct {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
d: u64,
|
||||
e: u64,
|
||||
f: u64,
|
||||
g: u64,
|
||||
h: u64
|
||||
}
|
||||
|
||||
#[no_stack_check]
|
||||
fn non_immediate_args(a: BigStruct, b: BigStruct) {
|
||||
println!("");
|
||||
}
|
||||
|
||||
#[no_stack_check]
|
||||
fn binding(a: i64, b: u64, c: f64) {
|
||||
let x = 0;
|
||||
println!("");
|
||||
}
|
||||
|
||||
#[no_stack_check]
|
||||
fn assignment(mut a: u64, b: u64, c: f64) {
|
||||
a = b;
|
||||
println!("");
|
||||
}
|
||||
|
||||
#[no_stack_check]
|
||||
fn function_call(x: u64, y: u64, z: f64) {
|
||||
println!("Hi!")
|
||||
}
|
||||
|
||||
#[no_stack_check]
|
||||
fn identifier(x: u64, y: u64, z: f64) -> u64 {
|
||||
x
|
||||
}
|
||||
|
||||
#[no_stack_check]
|
||||
fn return_expr(x: u64, y: u64, z: f64) -> u64 {
|
||||
return x;
|
||||
}
|
||||
|
||||
#[no_stack_check]
|
||||
fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 {
|
||||
x + y
|
||||
}
|
||||
|
||||
#[no_stack_check]
|
||||
fn if_expr(x: u64, y: u64, z: f64) -> u64 {
|
||||
if x + y < 1000 {
|
||||
x
|
||||
} else {
|
||||
y
|
||||
}
|
||||
}
|
||||
|
||||
#[no_stack_check]
|
||||
fn while_expr(mut x: u64, y: u64, z: u64) -> u64 {
|
||||
while x + y < 1000 {
|
||||
x += z
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
#[no_stack_check]
|
||||
fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 {
|
||||
loop {
|
||||
x += z;
|
||||
|
||||
if x + y > 1000 {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
immediate_args(1, true, 2.5);
|
||||
|
||||
non_immediate_args(
|
||||
BigStruct {
|
||||
a: 3,
|
||||
b: 4,
|
||||
c: 5,
|
||||
d: 6,
|
||||
e: 7,
|
||||
f: 8,
|
||||
g: 9,
|
||||
h: 10
|
||||
},
|
||||
BigStruct {
|
||||
a: 11,
|
||||
b: 12,
|
||||
c: 13,
|
||||
d: 14,
|
||||
e: 15,
|
||||
f: 16,
|
||||
g: 17,
|
||||
h: 18
|
||||
}
|
||||
);
|
||||
|
||||
binding(19, 20, 21.5);
|
||||
assignment(22, 23, 24.5);
|
||||
function_call(25, 26, 27.5);
|
||||
identifier(28, 29, 30.5);
|
||||
return_expr(31, 32, 33.5);
|
||||
arithmetic_expr(34, 35, 36.5);
|
||||
if_expr(37, 38, 39.5);
|
||||
while_expr(40, 41, 42);
|
||||
loop_expr(43, 44, 45);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user