| Age | Commit message (Collapse) | Author | Lines |
|
|
|
|
|
Improve formatting of doc code blocks
We don't currently apply automatic formatting to doc comment code blocks. As a
result, it has built up various idiosyncracies, which make such automatic
formatting difficult. Some of those idiosyncracies also make things harder for
human readers or other tools.
This PR makes a few improvements to doc code formatting, in the hopes of making
future automatic formatting easier, as well as in many cases providing net
readability improvements.
I would suggest reading each commit separately, as each commit contains one
class of changes.
|
|
|
|
Add `core::mem::DropGuard`
## 1.0 Summary
This PR introduces a new type `core::mem::DropGuard` which wraps a value and runs a closure when the value is dropped.
```rust
use core::mem::DropGuard;
// Create a new guard around a string that will
// print its value when dropped.
let s = String::from("Chashu likes tuna");
let mut s = DropGuard::new(s, |s| println!("{s}"));
// Modify the string contained in the guard.
s.push_str("!!!");
// The guard will be dropped here, printing:
// "Chashu likes tuna!!!"
```
## 2.0 Motivation
A number of programming languages include constructs like `try..finally` or `defer` to run code as the last piece of a particular sequence, regardless of whether an error occurred. This is typically used to clean up resources, like closing files, freeing memory, or unlocking resources. In Rust we use the `Drop` trait instead, allowing us to [never having to manually close sockets](https://blog.skylight.io/rust-means-never-having-to-close-a-socket/).
While `Drop` (and RAII in general) has been working incredibly well for Rust in general, sometimes it can be a little verbose to setup. In particular when upholding invariants are local to functions, having a quick inline way to setup an `impl Drop` can be incredibly convenient. We can see this in use in the Rust stdlib, which has a number of private `DropGuard` impls used internally:
- [library/alloc/src/vec/drain.rs](https://github.com/rust-lang/rust/blob/9982d6462bedf1e793f7b2dbd655a4e57cdf67d4/library/alloc/src/vec/drain.rs#L177)
- [library/alloc/src/boxed/thin.rs](https://github.com/rust-lang/rust/blob/9982d6462bedf1e793f7b2dbd655a4e57cdf67d4/library/alloc/src/boxed/thin.rs#L362)
- [library/alloc/src/slice.rs](https://github.com/rust-lang/rust/blob/9982d6462bedf1e793f7b2dbd655a4e57cdf67d4/library/alloc/src/slice.rs#L413)
- [library/alloc/src/collections/linked_list.rs](https://github.com/rust-lang/rust/blob/9982d6462bedf1e793f7b2dbd655a4e57cdf67d4/library/alloc/src/collections/linked_list.rs#L1135)
- [library/alloc/src/collections/binary_heap/mod.rs](https://github.com/rust-lang/rust/blob/9982d6462bedf1e793f7b2dbd655a4e57cdf67d4/library/alloc/src/collections/binary_heap/mod.rs#L1816)
- [library/alloc/src/collections/btree/map.rs](https://github.com/rust-lang/rust/blob/9982d6462bedf1e793f7b2dbd655a4e57cdf67d4/library/alloc/src/collections/btree/map.rs#L1715)
- [library/alloc/src/collections/vec_deque/drain.rs](https://github.com/rust-lang/rust/blob/9982d6462bedf1e793f7b2dbd655a4e57cdf67d4/library/alloc/src/collections/vec_deque/drain.rs#L95)
- [library/alloc/src/vec/into_iter.rs](https://github.com/rust-lang/rust/blob/9982d6462bedf1e793f7b2dbd655a4e57cdf67d4/library/alloc/src/vec/into_iter.rs#L488)
- [library/std/src/os/windows/process.rs](https://github.com/rust-lang/rust/blob/9982d6462bedf1e793f7b2dbd655a4e57cdf67d4/library/std/src/os/windows/process.rs#L320)
- [tests/ui/process/win-proc-thread-attributes.rs](https://github.com/rust-lang/rust/blob/9982d6462bedf1e793f7b2dbd655a4e57cdf67d4/tests/ui/process/win-proc-thread-attributes.rs#L17)
## 3.0 Design
This PR implements what can be considered about the simplest possible design:
1. A single type `DropGuard` which takes both a generic type `T` and a closure `F`.
2. `Deref` + `DerefMut` impls to make it easy to work with the `T` in the guard.
3. An `impl Drop` on the guard which calls the closure `F` on drop.
4. An inherent `fn into_inner` which takes the type `T` out of the guard without calling the closure `F`.
Notably this design does not allow divergent behavior based on the type of drop that has occurred. The [`scopeguard` crate](https://docs.rs/scopeguard/latest/scopeguard/index.html) includes additional `on_success` and `on_onwind` variants which can be used to branch on unwind behavior instead. However [in a lot of cases](https://github.com/rust-lang/rust/issues/143612#issuecomment-3053928328) this doesn’t seem necessary, and using the arm/disarm pattern seems to provide much the same functionality:
```rust
let guard = DropGuard::new((), |s| ...); // 1. Arm the guard
other_function(); // 2. Perform operations
guard.into_inner(); // 3. Disarm the guard
```
`DropGuard` combined with this pattern seems like it should cover the vast majority of use cases for quick, inline destructors. It certainly seems like it should cover all existing uses in the stdlib, as well as all existing uses in crates like [hashbrown](https://github.com/search?q=repo%3Arust-lang%2Fhashbrown%20guard&type=code).
## 4.0 Acknowledgements
This implementation is based on the [mini-scopeguard crate](https://github.com/yoshuawuyts/mini-scopeguard) which in turn is based on the [scopeguard crate](https://docs.rs/scopeguard). The implementations only differ superficially; because of the nature of the problem there is only really one obvious way to structure the solution. And the scopeguard crate got that right!
## 5.0 Conclusion
This PR adds a new type `core::mem::DropGuard` to the stdlib which adds a small convenience helper to create inline destructors with. This would bring the majority of the functionality of the `scopeguard` crate into the stdlib, which is the [49th most downloaded crate](https://crates.io/crates?sort=downloads) on crates.io (387 million downloads).
Given the actual implementation of `DropGuard` is only around 60 lines, it seems to hit that sweet spot of low-complexity / high-impact that makes for a particularly efficient stdlib addition. Which is why I’m putting this forward for consideration; thanks!
|
|
Fix CI for drop_guard
fix CI
fix all tidy lints
fix tidy link
add first batch of feedback from review
Add second batch of feedback from review
add third batch of feedback from review
fix failing test
Update library/core/src/mem/drop_guard.rs
Co-authored-by: Ruby Lazuli <general@patchmixolydic.com>
fix doctests
Implement changes from T-Libs-API review
And start tracking based on the tracking issue.
fix tidy lint
|
|
Because doc code does not get automatically formatted, some doc code has
creative placements of comments that automatic formatting can't handle.
Reformat those comments to make the resulting code support standard Rust
formatting without breaking; this is generally an improvement to
readability as well.
Some comments are not indented to the prevailing indent, and are instead
aligned under some bit of code. Indent them to the prevailing indent,
and put spaces *inside* the comments to align them with code.
Some comments span several lines of code (which aren't the line the
comment is about) and expect alignment. Reformat them into one comment
not broken up by unrelated intervening code.
Some comments are placed on the same line as an opening brace, placing
them effectively inside the subsequent block, such that formatting would
typically format them like a line of that block. Move those comments to
attach them to what they apply to.
Some comments are placed on the same line as a one-line braced block,
effectively attaching them to the closing brace, even though they're
about the code inside the block. Reformat to make sure the comment will
stay on the same line as the code it's commenting.
|
|
Update core::mem::copy documentation
Update the documentation of `core::mem::copy` to include a `const` on the definition of the function.
|
|
address clippy formatting nits
- int_log10.rs: change top level doc comments to outer
- collect.rs: remove empty line after doc comment
- clippy fix: markdown indentation for indented items after line break: a markdown list item continued over multiples lines, but those following lines which are part of the same item are not indented
- clippy fix: bound in one place: when there is a bound in angle brackets and another bound on the same variable in a where clause
|
|
|
|
signature
|
|
|
|
|
|
|
|
|
|
|
|
Unimplement unsized_locals
Implements https://github.com/rust-lang/compiler-team/issues/630
Tracking issue here: https://github.com/rust-lang/rust/issues/111942
Note that this just removes the feature, not the implementation, and does not touch `unsized_fn_params`. This is because it is required to support `Box<dyn FnOnce()>: FnOnce()`.
There may be more that should be removed (possibly in follow up prs)
- the `forget_unsized` function and `forget` intrinsic.
- the `unsized_locals` test directory; I've just fixed up the tests for now
- various codegen support for unsized values and allocas
cc ``@JakobDegen`` ``@oli-obk`` ``@Noratrieb`` ``@programmerjake`` ``@bjorn3``
``@rustbot`` label F-unsized_locals
Fixes rust-lang/rust#79409
|
|
|
|
|
|
|
|
|
|
|
|
`MaybeUninit` inherent slice methods part 2
These were moved out of #129259 since they require additional libs-api approval. Tracking issue: #117428.
New API surface:
```rust
impl<T> [MaybeUninit<T>] {
// replacing fill; renamed to avoid conflict
pub fn write_filled(&mut self, value: T) -> &mut [T] where T: Clone;
// replacing fill_with; renamed to avoid conflict
pub fn write_with<F>(&mut self, value: F) -> &mut [T] where F: FnMut() -> T;
// renamed to remove "fill" terminology, since this is closer to the write_*_of_slice methods
pub fn write_iter<I>(&mut self, iter: I) -> (&mut [T], &mut Self) where I: Iterator<Item = T>;
}
```
Relevant motivation for these methods; see #129259 for earlier methods' motiviations.
* I chose `write_filled` since `filled` is being used as an object here, whereas it's being used as an action in `fill`.
* I chose `write_with` instead of `write_filled_with` since it's shorter and still matches well.
* I chose `write_iter` because it feels completely different from the fill methods, and still has the intent clear.
In all of the methods, it felt appropriate to ensure that they contained `write` to clarify that they are effectively just special ways of doing `MaybeUninit::write` for each element of a slice.
Tracking issue: https://github.com/rust-lang/rust/issues/117428
r? libs-api
|
|
Expand and organize `offset_of!` documentation.
* Give example of how to get the offset of an unsized tail field (prompted by discussion <https://github.com/rust-lang/rust/pull/133055#discussion_r1986422206>).
* Specify the return type.
* Add section headings.
* Reduce “Visibility is respected…”, to a single sentence.
* Move `offset_of_enum` documentation to unstable book (with link to it).
* Add `offset_of_slice` documentation in unstable book.
r? Mark-Simulacrum
|
|
Remove `#[cfg(not(test))]` gates in `core`
These gates are unnecessary now that unit tests for `core` are in a separate package, `coretests`, instead of in the same files as the source code. They previously prevented the two `core` versions from conflicting with each other.
|
|
This means that things like `<usize as Step>::forward_unchecked` and `<PartialOrd for f32>::le` will inline even if we've already done a bunch of inlining to find the calls to them.
|
|
|
|
* Give example of how to get the offset of an unsized tail field
(prompted by discussion <https://github.com/rust-lang/rust/pull/133055#discussion_r1986422206>).
* Specify the return type.
* Add section headings.
* Reduce “Visibility is respected…”, to a single sentence.
|
|
|
|
Use `std::mem::{size_of, size_of_val, align_of, align_of_val}` from the
prelude instead of importing or qualifying them.
These functions were added to all preludes in Rust 1.80.
|
|
These gates are unnecessary now that unit tests for `core` are in a
separate package, `coretests`, instead of in the same files as the
source code. They previously prevented the two `core` versions from
conflicting with each other.
|
|
remove `MaybeUninit::uninit_array`
Closes #134584.
Closes #66845.
The future of this unstable method was described in https://github.com/rust-lang/rust/pull/125082#issuecomment-2161242816. Since `inline_const` was stabilized in 1.79 (4 stable releases away) and no one expressed interest for keeping it in https://github.com/rust-lang/rust/issues/96097, I think it can be removed now as it is not a stable method.
|
|
|
|
Apply unsafe_op_in_unsafe_fn to the standard library
This applies unsafe_op_in_unsafe_fn to the standard library in preparation for updating to Rust 2024.
Closes https://github.com/rust-lang/rust/issues/127747 (I think?) cc ``@workingjubilee``
I have been testing a variety of targets, and I feel like they are all pretty much covered. I'll continue doing some testing async, but I don't expect to catch any more.
|
|
|
|
|
|
|
|
No longer breaks if `MaybeUninit` moves modules (technically it could break if `MaybeUninit` were renamed but realistically that will never happen)
|
|
|
|
|
|
|
|
|
|
|
|
docs: `transmute<&mut T, &mut MaybeUninit<T>>` is unsound when exposed to safe code
Closes #66699
On my system (Edit: And also in the [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=90529e2a9900599cb759e4bfaa5b5efe)) the example program terminates with an unpredictable exit code:
```console
$ cargo +nightly build && target/debug/bin ; echo $?
255
$ cargo +nightly build && target/debug/bin ; echo $?
253
```
And miri considers the code to have undefined behavior:
```console
$ cargo +nightly miri run
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
--> src/main.rs:12:24
|
12 | std::process::exit(*code); // UB! Accessing uninitialized memory
| ^^^^^ using uninitialized data, but this operation requires initialized memory
|
error: aborting due to 1 previous error
```
|
|
Asserts the maximum value that can be returned from `Vec::len`
Currently, casting `Vec<i32>` to `Vec<u32>` takes O(1) time:
```rust
// See <https://godbolt.org/z/hxq3hnYKG> for assembly output.
pub fn cast(vec: Vec<i32>) -> Vec<u32> {
vec.into_iter().map(|e| e as _).collect()
}
```
But the generated assembly is not the same as the identity function, which prevents us from casting `Vec<Vec<i32>>` to `Vec<Vec<u32>>` within O(1) time:
```rust
// See <https://godbolt.org/z/7n48bxd9f> for assembly output.
pub fn cast(vec: Vec<Vec<i32>>) -> Vec<Vec<u32>> {
vec.into_iter()
.map(|e| e.into_iter().map(|e| e as _).collect())
.collect()
}
```
This change tries to fix the problem. You can see the comparison here: <https://godbolt.org/z/jdManrKvx>.
|
|
safe code
In the playground the example program terminates with an unpredictable exit
code. The undefined behavior is also detected by miri:
error: Undefined Behavior: using uninitialized data
|
|
This commit splits the `#[rustc_deny_explicit_impl(implement_via_object = ...)]` attribute
into two attributes `#[rustc_deny_explicit_impl]` and `#[rustc_do_not_implement_via_object]`.
This allows us to have special traits that can have user-defined impls but do not have the
automatic trait impl for trait objects (`impl Trait for dyn Trait`).
|
|
|
|
stabilize const_{size,align}_of_val
FCP passed [here](https://github.com/rust-lang/rust/issues/46571#issuecomment-2460285288).
Fixes https://github.com/rust-lang/rust/issues/46571.
|
|
|