Announcing Rust 1.15

Feb. 2, 2017 · The Rust Core Team

The Rust team is happy to announce the latest version of Rust, 1.15.0. Rust is a systems programming language focused on safety, speed, and concurrency.

If you have a previous version of Rust installed, getting Rust 1.15 is as easy as:

$ rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website, and check out the detailed release notes for 1.15.0 on GitHub. 1443 patches were landed in this release.

What's in 1.15.0 stable

Rust 1.15 sees an extremely eagerly-awaited feature land on stable: custom derive! To review, in Rust, you've always been able to automatically implement some traits through the derive attribute:

#[derive(Debug)]
struct Pet {
    name: String,
}

The Debug trait is then implemented for Pet, with vastly less boilerplate. However, this only worked for traits provided as part of the standard library; it was not customizable. With Rust 1.15, it now is. That means, if you want to turn your Pet into JSON, it's as easy as adding Serde to your Cargo.toml:

[dependencies]
serde = "0.9"
serde_derive = "0.9"
serde_json = "0.9"

And adding another trait to your Pet:

#[macro_use]
extern crate serde_derive;

extern crate serde_json;

#[derive(Serialize, Deserialize, Debug)]
struct Pet {
    name: String,
}

fn main() {
    let pet = Pet { name: String::from("Ferris") };

    let serialized = serde_json::to_string(&pet).unwrap();
    println!("serialized = {}", serialized);

    let deserialized: Pet = serde_json::from_str(&serialized).unwrap();
    println!("deserialized = {:?}", deserialized);
}

This will output:

serialized = {"name":"Ferris"}
deserialized = Pet { name: "Ferris" }

Another common use-case is Diesel. Say we had a database of Pets. We could fetch them like this:

// some extern crate and use lines elided here

#[derive(Queryable)]
struct Pet {
    name: String,
}

fn main() {
    use diesel_demo::schema::pets::dsl::*;

    let connection = establish_connection();
    let results = pets
        .limit(5)
        .load::<Pet>(&connection)
        .expect("Error loading pets");

    println!("Displaying {} pets", results.len());
    for pet in results {
        println!("{}", pet.name);
    }
}

For full instructions, see the website.

These kinds of libraries are extremely powerful, but rely on custom derive for ergonomics. While these libraries worked on Rust stable previously, they were not as nice to use, so much so that we often heard from users "I only use nightly because of Serde and Diesel." The use of custom derive is one of the most widely used nightly-only features. As such, RFC 1681 was opened in July of last year to support this use-case. The RFC was merged in August, underwent a lot of development and testing, and now reaches stable today!

To find out how to write your own custom derives, see the chapter of "The Rust Programming Language".

While we've said "Serde and Diesel" a number of times here, there's a lot of other cool things you can do with custom derive: see derive-new for another example. See the syn crate's reverse dependencies for more. (syn is important for writing custom derives, see the book chapter, linked above, for more.) Custom derive was also known as "macros 1.1", as it includes the infrastructure for supporting even more compile-time powers of Rust, nicknamed "macros 2.0." Expect to hear more about this space in future releases.

Other improvements

The build system for Rust has been re-written in Rust, using Cargo. It is now the default. This process has been long, but has finally borne fruit. Given that all Rust development happens on the master branch, we've been using it since December of last year, and it's working well. There is an open PR to remove the Makefiles entirely, landing in Rust 1.17. This will pave the way for rustc to use packages from crates.io in the compiler like any other Rust project, and is a further demonstration of the maturity of Cargo.

Rust has gained Tier 3 support for i686-unknown-openbsd, MSP430, and ARMv5TE.

A number of compiler performance improvements have landed. We continue to work on making the compiler faster. Expect to see more in the future!

As a smaller improvement, ?Sized can now be used in where clauses. In other words:

struct Foo<T: ?Sized> {
    f: T,
}

struct Foo<T> where T: ?Sized {
    f: T,
}

This second form is now accepted, and is equivalent to the first.

See the detailed release notes for more.

Library stabilizations

The slice::sort algorithm has been rewritten, and is much, much, much faster. It is a hybrid merge sort, drawing influences from Timsort. Previously it was a straightforward merge sort.

If you had a Vec<T> where T: Copy, and you called extend on it, your code will now be a lot faster.

Speaking of things getting faster, chars().count(), chars().last(), and char_indices().last() are too!

Chinese characters now display correctly in fmt::Debug.

There were a number of functions stabilized as well:

See the detailed release notes for more.

Cargo features

Cargo will now emit a warning if you have a file named build.rs at the top level of a package, but don't have a build = "build.rs" annotation. This is in anticipation of inferring that build.rs at the top level is always a build script, but is a warning right now for compatibility reasons. Previously, all build scripts required configuration, but this convention was strong within the community, so we're going to encode it into Cargo.

In this release, Cargo build scripts no longer have access to the OUT_DIR environment variable at build time via env!("OUT_DIR"). They should instead check the variable at runtime with std::env. That the value was set at build time was a bug, and incorrect when cross-compiling. Please check what your packages are doing and update to use std::env!

The cargo test command has gained support for a --all flag, which is useful when you have a workspace.

We now Compile statically against the MSVC CRT on Windows, and Link OpenSSL statically on Mac OS X.

See the detailed release notes for more.

Contributors to 1.15.0

In this part of the release announcements, we usually post a list of contributors. However, we've recently started a new initiative, "Thanks!", to do this in a more comprehensive way. One issue with this section is that it only counted contributions to the rust-lang/rust repository; those who committed to Cargo weren't thanked, for example. We also had to manually generate this list, which wasn't terrible, but running the correct git commands to determine who contributed is exactly what code is good for!

As such, you can now visit https://thanks.rust-lang.org/ to see more comprehensive contribution calculations. If you prefer, we also have an alias at https://❤.rust-lang.org as well. For now, this will only show what we've shown in previous release posts. We do have one additional feature, which is an all-time contributions list, sorted by commit count. That's located here: https://thanks.rust-lang.org/rust/all-time

We have done some of the needed backend work to enable more repositories than only rust-lang/rust, but it's not quite done yet. If you'd like to get involved, please check out thanks on GitHub!

We had 137 individuals contribute to Rust 1.15. Thanks!