Skip to content

Commit 8733a2f

Browse files
committed
Add blog post for 1.51.0
1 parent d0bdd7d commit 8733a2f

File tree

1 file changed

+211
-0
lines changed

1 file changed

+211
-0
lines changed

posts/2021-03-25-Rust-1.51.0.md

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
---
2+
layout: post
3+
title: "Announcing Rust 1.51.0"
4+
author: The Rust Release Team
5+
release: true
6+
---
7+
8+
The Rust team is happy to announce a new version of Rust, 1.51.0. Rust is a
9+
programming language that is empowering everyone to build reliable and
10+
efficient software.
11+
12+
If you have a previous version of Rust installed via rustup, getting Rust
13+
1.51.0 is as easy as:
14+
15+
```console
16+
rustup update stable
17+
```
18+
19+
If you don't have it already, you can [get `rustup`][install]
20+
from the appropriate page on our website, and check out the
21+
[detailed release notes for 1.51.0][notes] on GitHub.
22+
23+
[install]: https://www.rust-lang.org/install.html
24+
[notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1510-2021-03-25
25+
26+
## What's in 1.51.0 stable
27+
This release represents one of the largest additions to the Rust language and cargo in quite a while. With the stabilization of const generics, and the new feature resolver, along with more minor additions such as the `split-debuginfo` option, and the `addr_of!` API. Let's dive right into it!
28+
29+
30+
### Const Generics MVP
31+
Before this release, Rust allowed you to haves your types be parameterized over lifetimes or types. For example if we wanted to have a `struct` that is generic over an array of 32 items, we'd write the following:
32+
33+
```rust
34+
struct FixedArray<T> {
35+
// ^^^ Type generic definition
36+
list: [T; 32]
37+
// ^ Where we're using it.
38+
}
39+
```
40+
41+
If we then use `FixedArray<u8>`, the compiler will make a monomorphic version of `FixedArray` that looks like:
42+
43+
```
44+
struct FixedArray<u8> {
45+
list: [u8; 32]
46+
}
47+
```
48+
49+
This is a powerful feature that allows you to write reusable code with no runtime overhead. Enabling to have types that fit a wide variety of use-cases and types. However, until this release it hasn't been possible to easily be generic over the *values* of those types. This was most notable in arrays where they include their length in their type definition (`[T; N]`). Now with 1.51.0 you can write code that is generic over the values of any integer, `bool`, or `char` type! (Using `struct` or `enum` values is still unstable.)
50+
51+
This change now lets us have our own array struct that's generic over its type *and* its length. Let's look at an example definition, and how it can be used.
52+
53+
```rust
54+
struct Array<T, const LENGTH: usize> {
55+
// ^^^^^^^^^^^^^^^^^^^ Const generic definition.
56+
list: [T; LENGTH]
57+
// ^^^^^^ We use it here.
58+
}
59+
```
60+
61+
Now if we then used `Array<u8, 32>`, the compiler will make a monomorphic version of `Array` that looks like:
62+
63+
```rust
64+
struct Array<u8, 32> {
65+
list: [u8; 32]
66+
}
67+
```
68+
69+
Const generics also allows to write our methods in a new way. Let's see what a `fn last(&self) -> Option<&T>` implementation could look like:
70+
71+
```rust
72+
impl<T, const LENGTH: usize> Array<T, LENGTH> {
73+
fn last(&self) -> Option<&T> {
74+
if LENGTH == 0 {
75+
// ^^^^^^^^^^^ This is always `true` for `Array<T, 0>`.
76+
None
77+
} else {
78+
Some(&self.list[LENGTH - 1])
79+
}
80+
}
81+
}
82+
```
83+
84+
Const generics adds an important new tool for library designers in creating new, powerful compile-time safe APIs. If you'd like to learn more about const generics you can also check out the ["Const Generics MVP Hits Beta"][const-generics-blog] blog post for more information about the feature and its current restrictions. We can't wait to see what new libraries and APIs you create!
85+
86+
[const-generics-blog]: https://blog.rust-lang.org/2021/02/26/const-generics-mvp-beta.html
87+
88+
### `array::IntoIter` Stabilisation
89+
As part of const generics stabilising, we're also stabilising a new API that uses it called `array::IntoIter`. `IntoIter` allows you to create a by value iterator over any array. Previously you had to use `[T]`'s (a slice) iterator implementation which returned `&T`, which you then needed to read and copy. Now you can directly iterate over the values without additional copies. *Note:* that `IntoIter::new` may be deprecated once it is possible for arrays to implement `IntoIterator` directly.
90+
91+
```rust
92+
fn main() {
93+
let array = [1, 2, 3, 4, 5];
94+
95+
// Previously
96+
for item in array.iter().copied() {
97+
println!("{}", item);
98+
}
99+
100+
// Now
101+
for item in std::array::IntoIter::new(array) {
102+
println!("{}", item);
103+
}
104+
}
105+
```
106+
107+
### Cargo's New Feature Resolver
108+
Dependency management is a hard problem, and one of the hardest parts of it is just picking what *version* of a dependency to use when it's depended on by two different packages. This doesn't just include its version number, but also what features are or aren't enabled for the package. Cargo's default behaviour is to merge features for a single package. Let's say you had a dependency called `foo` with features A and B, which was being used by packages `bar` and `baz`, but `bar` depends on `foo+A` and `baz` depends on `foo+B`. Cargo will merge both of those features and compile `foo` as `foo+AB`. This has a benefit that you only have to compile `foo` once, and then it can reused for both `foo` and `bar`.
109+
110+
However, this also comes with a downside. What if `A` and `B` are incompatible? What if your own code is compatible with `foo` but not `foo+A`? A common example of this in the ecosystem is the optional `std` feature included in many `#![no_std]` crates, that allows crates to provide added functionality when `std` is available. Now imagine you want to use the `#![no_std]` version of `foo` in your `#![no_std]` binary, and use the `foo` at build time in your `build.rs`. If your build time dependency depends on `foo+std`, your binary now also depends on `foo+std`, which means it will no longer compile because `std` is not available for your target platform.
111+
112+
This has been a long-standing issue in cargo, and with this release there's a new `resolver` option in your `Cargo.toml`, where you can set `resolver="2"` to tell cargo to try a new approach to resolving features. You can check out [RFC 2957] for a detailed description of the behaviour, which can be summarised as follows.
113+
114+
- **Dev dependencies** — When a package is shared as a normal dependency and a dev-dependency, the dev-dependency features are only enabled if the current build is including dev-dependencies.
115+
- **Host Dependencies** — When a package is shared as a normal dependency and a build-dependency or proc-macro, the features for the normal dependency are kept independent of the build-dependency or proc-macro.
116+
- **Target dependencies** — When a package appears multiple times in the build graph, and one of those instances is a target-specific dependency, then the features of the target-specific dependency are only enabled if the target is currently being built.
117+
118+
While this can lead to some crates compiling more than once, this should provide a much more intuitive development experience when using features with cargo. If you'd like to know more, you can also read the ["Feature Resolver"][feature-resolver@2.0] section in the Cargo Book for more information. We'd like to thank the cargo team and everyone involved for all their hard work in designing and implementing this new feature (resolver)!
119+
120+
```toml
121+
[package]
122+
resolver = "2"
123+
# Or if you're using a workspace
124+
[workspace]
125+
resolver = "2"
126+
```
127+
128+
[rfc 2957]: https://rust-lang.github.io/rfcs/2957-cargo-features2.html
129+
[feature-resolver@2.0]: https://doc.rust-lang.org/nightly/cargo/reference/features.html#feature-resolver-version-2
130+
131+
### Splitting Debug Information
132+
While not often highlighted in the release, the Rust teams are constantly working on improving Rust's compile times, and this release marks one of the biggest improvements in a long time for Rust on macOS platforms. Debug information is code that maps the binary code back to your source code, so that the program can give you more information about what went wrong at run time. In macOS this is done with a tool called `dsymutil` which collects all the debug information into a single `.dSYM` folder.
133+
134+
This tool provides a lot of benefits, however, one of the drawbacks has been that `dsymutil` is not really compatible with incremental recompilation. This means that even when you make a small change such as a function name, `dsymutil` will need to run over the entire final binary to produce the final `.dSYM` folder. This can sometimes add a lot to the build time, (especially for larger projects), but this has been a necessary step as without it Rust wouldn't be able to parse debug info on macOS.
135+
136+
With the implementation of the Rust-based `backtrace` crate backend, we can now parse debuginfo even without running `dsymutil`. This can significantly speed up builds that include debuginfo and significantly reduce the amount of disk space used. We haven't run extensive benchmarks but have seen a lot of anecdata of people's builds building a lot faster on macOS with this behaviour.
137+
138+
You can enable this new behaviour by setting the `-Csplit-debuginfo=unpacked` flag when running `rustc`, or by setting the [`split-debuginfo`] `[profile]` option to `unpacked` in Cargo. The "unpacked" option instructs rustc to leave the .o object files in the build output directory instead of deleting them, and skips the step of running dsymutil. Rust's backtrace support is smart enough to know how to find these .o files. Tools such as lldb also know how to do this. This should work as long as you don't need to move the binary to a different location while retaining the debug information.
139+
140+
```toml
141+
[profile.dev]
142+
split-debuginfo = "unpacked"
143+
```
144+
145+
[`split-debuginfo`]: https://doc.rust-lang.org/nightly/cargo/reference/profiles.html#split-debuginfo
146+
147+
### Stabilized APIs
148+
149+
In total, this release saw the stabilisation of 18 new methods for various types like `slice` and `Peekable`. One notable addition is the stabilisation of `ptr::addr_of!` and `ptr::addr_of_mut!`, which allow you to create unaligned references to data. Previously this wasn't possible because Rust requires `&/&mut` to be aligned and point to initialized data, and `&addr as *const _` would cause undefined behaviour as `&addr` needs to be aligned. These two macros now let you safely create unaligned references.
150+
151+
```rust
152+
use std::ptr;
153+
154+
#[repr(packed)]
155+
struct Packed {
156+
f1: u8,
157+
f2: u16,
158+
}
159+
160+
let packed = Packed { f1: 1, f2: 2 };
161+
// `&packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
162+
let raw_f2 = ptr::addr_of!(packed.f2);
163+
assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
164+
```
165+
166+
The following methods were stabilised.
167+
168+
- [`Arc::decrement_strong_count`]
169+
- [`Arc::increment_strong_count`]
170+
- [`Once::call_once_force`]
171+
- [`Peekable::next_if_eq`]
172+
- [`Peekable::next_if`]
173+
- [`Seek::stream_position`]
174+
- [`array::IntoIter`]
175+
- [`panic::panic_any`]
176+
- [`ptr::addr_of!`]
177+
- [`ptr::addr_of_mut!`]
178+
- [`slice::fill_with`]
179+
- [`slice::split_inclusive_mut`]
180+
- [`slice::split_inclusive`]
181+
- [`slice::strip_prefix`]
182+
- [`slice::strip_suffix`]
183+
- [`str::split_inclusive`]
184+
- [`sync::OnceState`]
185+
- [`task::Wake`]
186+
187+
[`Once::call_once_force`]: https://doc.rust-lang.org/stable/std/sync/struct.Once.html#method.call_once_force
188+
[`sync::OnceState`]: https://doc.rust-lang.org/stable/std/sync/struct.OnceState.html
189+
[`panic::panic_any`]: https://doc.rust-lang.org/stable/std/panic/fn.panic_any.html
190+
[`slice::strip_prefix`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.strip_prefix
191+
[`slice::strip_suffix`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.strip_prefix
192+
[`Arc::increment_strong_count`]: https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.increment_strong_count
193+
[`Arc::decrement_strong_count`]: https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.decrement_strong_count
194+
[`slice::fill_with`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.fill_with
195+
[`ptr::addr_of!`]: https://doc.rust-lang.org/nightly/std/ptr/macro.addr_of.html
196+
[`ptr::addr_of_mut!`]: https://doc.rust-lang.org/nightly/std/ptr/macro.addr_of_mut.html
197+
[`array::IntoIter`]: https://doc.rust-lang.org/nightly/std/array/struct.IntoIter.html
198+
[`slice::split_inclusive`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_inclusive
199+
[`slice::split_inclusive_mut`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_inclusive_mut
200+
[`str::split_inclusive`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_inclusive
201+
[`task::Wake`]: https://doc.rust-lang.org/nightly/std/task/trait.Wake.html
202+
[`Seek::stream_position`]: https://doc.rust-lang.org/nightly/std/io/trait.Seek.html#method.stream_position
203+
[`Peekable::next_if`]: https://doc.rust-lang.org/nightly/std/iter/struct.Peekable.html#method.next_if
204+
[`Peekable::next_if_eq`]: https://doc.rust-lang.org/nightly/std/iter/struct.Peekable.html#method.next_if_eq
205+
206+
### Other changes
207+
208+
There are other changes in the Rust 1.51.0 release: check out what changed in [Rust](https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1510-2021-03-25), [Cargo](https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-151-2021-03-25), and [Clippy](https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-151).
209+
210+
### Contributors to 1.51.0
211+
Many people came together to create Rust 1.51.0. We couldn't have done it without all of you. [Thanks!](https://thanks.rust-lang.org/rust/1.51.0/)

0 commit comments

Comments
 (0)