Introducing `cxx-async`

I'm happy to announce a new Rust crate that I've been working on for a while at Meta: cxx-async. cxx-async is an extension to the cxx crate that allows for bidirectional interoperability between C++ coroutines and asynchronous Rust functions. With it, you can await C++ coroutines and co_await Rust functions; as much as possible, everything "just works". The biggest practical benefit of C++ coroutine interoperability is elimination of awkward callback patterns when interfacing with C++.

Read More

Plans for 2019

Many people have asked me what I'm working on lately, and I thought I'd give a quick rundown of my status and plans for 2019. I intend to keep this post updated with the status of projects as they progress.

Read More

Determining Triangle Geometry in Fragment Shaders

When doing GPU programming, it's sometimes useful to determine the positions of the vertices of the current triangle primitive in a fragment shader. The usual advice here is to use a geometry or tessellation shader to gather up the positions and pass them along explicitly to the fragment shader. It turns out, though, that there is a relatively straightforward solution without any extra shader stages using the standard derivative functions dFdx and dFdy. It works as long as the (non-perspective-correct) barycentric coordinates for the current fragment are available. I'm sure I'm not the first one to come up with this technique, but a quick search didn't find any explanations of it, so I thought I'd write it up, because it turned out to be useful in Pathfinder.

Read More

Pathfinder, a fast GPU-based font rasterizer in Rust

Ever since some initial discussions with Raph Levien (author of font-rs) at RustConf last September, I've been thinking about ways to improve vector graphics rendering using modern graphics hardware, specifically for fonts. These ideas began to come together in December, and over the past couple of months I've been working on actually putting them into a real, usable library. They've proved promising, and now I have some results to show.

Read More

Revamped Parallel Layout in Servo

Over the past week I've submitted a series of pull requests that significantly revamp the way parallel layout works in Servo. Originally I did this work to improve performance, but it's also turned out to be necessary to implement more advanced CSS 2.1 features. As it's a fairly novel algorithm (as far as I'm aware) I'd like to take some time to explain it. I'll start with where we are in Servo head and explain how it evolved into what's in my branch. This post assumes a little knowledge about how browser engines work, but little else.

Read More

Removing Garbage Collection From the Rust Language

I've been floating ways to simplify the memory management story in Rust around the core team lately. Memory management is a contentious topic, since we've worked hard to get to the current state of things, and with the push toward stability lately, there is a (quite reasonable!) resistance to any changes at this state. Still, I think the current memory management story in Rust is worth revisiting, as the current state of things may cause us problems down the line. Working with Dave Herman and Niko Matsakis, I've formulated a fairly concrete proposal at this point. The basic idea is to remove garbage collection from the core language and relegate it to the standard library, with a minimal set of language hooks in place to allow for flexible, pluggable automatic memory management.

Read More

Performance of Sequential Rust Programs

Although Rust is designed for parallel programs, it is important that the performance of single-threaded, sequential programs not suffer in its design. As far as Servo is concerned, sequential performance is still important in many domains that a Web browser engine must compete in.

Read More

A Hard Case for Memory Safety

Quick quiz: In this C++ program, is the definition of munge guaranteed to be memory safe? (Assume that the definition of increment_counter uses only modern C++ idioms and doesn't do anything like dereference an invalid pointer.)

Read More

An Overview of Memory Management in Rust

One of the key features of Rust that sets it apart from other new languages is that its memory management is manual—the programmer has explicit control over where and how memory is allocated and deallocated. In this regard, Rust is much more like C++ than like Java, Python, or Go, to name a few. This is an important design decision that makes Rust able to function in performance-critical domains that safe languages previously haven't been able to—top-of-the line games and Web browsers, for example—but it adds a nontrivial learning curve to the language.

Read More

Which Pointer Should I Use?

Deciding whether to use a managed @ pointer or an owned ~ pointer to allocate memory is one of the most frequent sources of confusion for newcomers to Rust. There are two main angles to consider when deciding whether to use an @ pointer or a ~ pointer in Rust: memory management and concurrency. I'll cover each in turn.

Read More

The New Borrow Check in a Nutshell

If you've used Rust for any period of time, you've probably been bitten by the mysterious borrow check—the compiler pass responsible for preventing iterator invalidation, as well as a few other dangling pointer scenarios. The current iteration of the borrow check enforces a fairly complex set of rules. Because the rules were hard to understand and ruled out too many valid programs, we were never really satisfied with the analysis; without a simple set of rules to follow, programmers will get frustrated and give up. To remedy this, Niko has proposed a revamp of the borrow checker known as "Imagine Never Hearing the Phrase 'Aliasable, Mutable' Again". This has mostly been implemented in a pull request now, so I'd like to take the opportunity to explain the new rules. I'm particularly excited about this change because now the entire set of borrow check rules are simple enough to boil down to one principle.

Read More

A Tour of Vector Representations

One aspect of Rust that's often confusing to newcomers is its treatment of strings and vectors (also known as arrays or lists). As a result of its focus on systems programming, Rust has a somewhat lower-level concept of a vector than most other languages do. As part of an overall goal to make Rust easy to understand, I thought I'd write up a quick tour of the way other languages' vectors work from the perspective of the machine in order to make it easier to map these concepts into Rust.

Read More

Typestate Is Dead, Long Live Typestate!

One well-known fact about Rust is that the typestate system, which was one of the most unique aspects of the language early on, was dropped in Rust 0.4. The reason was that "in practice, it found little use" (courtesy of Wikipedia), which is fairly accurate. However, what's less well known is that, in the meantime, Rust gained the building blocks necessary for typestate via its uniqueness typing system. With the right patterns, most of the safety guarantees that typestate enabled can be achieved, although it's not as easy to use.

Read More

Unique Pointers Aren't Just About Memory Management

One of the most unusual features of Rust, especially when compared to languages that aren't C++, is the three types of pointers: borrowed pointers (&T), unique pointers (~T), and managed pointers (@T). Most people quite rightly ask "why three pointers? Isn't one enough?" The usual answer is that unique pointers help with manual memory management:

Read More

A Gentle Introduction to Traits in Rust

Rust traits pack a lot of flexibility into a simple system, and they're one of my favorite features of the language. But as a result of the rapid pace of the language's development, there's been a fair amount of confusion as to how they work. As such, I figured I'd write up a quick tutorial explaining why and how to use them.

Read More

Maximally Minimal Classes for Rust

Now that classes have been implemented as per the original proposal, the other Rusters and I have been starting to get a feel for the way they work out in practice. The results are positive, but not optimal. Although they definitely succeeded in avoiding the rigidity of traditional object-oriented languages like Java, they still have two basic problems: (1) they feel somewhat out of place with the rest of the language; and (2) they're still too heavyweight. Nevertheless, the functionality that they enabled is important, and we shouldn't sacrifice it.

Read More

Why Lifetimes?

One of the most unique new features of Rust is its slowly-growing support for regions—or lifetimes, as some of us core developers like to call them. As lifetimes aren't found in any mainstream languages, I thought I'd expand upon why we want them and how they can be used to improve memory management for performance (especially interactive performance) without sacrificing safety. In this first post I'll explain why existing memory models weren't enough and why we went searching for alternatives. Here I'm assuming basic knowledge of garbage collection, reference counting, and malloc/free, but nothing more.

Read More