This article was written in collaboration with Neil Mitchell, a Software Engineer in the Developer Infrastructure organization at Facebook.
The Rust library Gazebo contains a collection of well-tested Rust utilities. These aren’t meant to be deep or complex ideas, just small things we think can make the experience of Rust programmers a little bit easier. This post is the first in a series that is going to explore a few things in Gazebo. Let's start with Prelude.
The Gazebo Prelude includes 5 extension traits, which add extra methods to Vec, slice, Option, str and iterators. These are meant to be small helpers which make common patterns slightly more concise or slightly less error prone. Our hope is that some of these methods might be useful enough to enter the standard library one day. For example, it’s not uncommon to see the following pattern in Rust code:
let ys = xs.iter().map(|x| x.abs()).collect::<Vec<_>>();
We have a vector of integers, and want to produce a vector of integers by mapping over each element. To do that, we first convert it to an iterator, then map, and finally collect it back. Unfortunately, Rust can’t figure out the result type, so we need a type annotation on the collect call. Rust iterators are powerful, efficient and composable, so it’s great to be able to do such a transformation so easily.
While this code isn’t terrible, this pattern crops up a lot, so it’s worth simplifying a bit:
use gazebo::prelude::*; let ys = xs.map(|x| x.abs());
Now the code expresses our intent much more directly. The map function works on both Vec and slices, with a corresponding into_map which takes ownership of the elements, but only works on Vec. Under the hood it does exactly the same thing, using iterators.
Other extension methods in Prelude apply to str, giving more flexible methods for splitting strings. For example:
use gazebo::prelude::*; assert_eq!("test".split1('e'), ("t", "st")); assert_eq!("test".split1_opt('e'), Some(("t", "st"))); assert_eq!("test".trim_start_match("tes"), "t"); assert_eq!("test".trim_start_match_opt("tes"), Some("t"));
We’ve found that these methods provide a bit of help when trying to do “light” parsing of a string - simpler and less powerful than a regex or full parser-combinator library like nom, but useful nonetheless. Sadly, these string methods are only available with the Rust nightly, as building on top of the flexible string pattern matching requires the unstable pattern feature.
Previous versions of the Gazebo library contained the functions that showed up in the Rust standard library as strip_prefix and strip_suffix, so those are no longer available in Gazebo.
While there are other methods in the Prelude, we’ve found these are the most common in our code. To see the others, visit the documentation.
We hope that this blog helps you understand the Prelude module, how to use it and gives you good insight into what it does. Look out for our next blog in this series, where we discuss the Dupe module, which encodes the pattern of cheap Clone.
We at Facebook believe that Rust is an outstanding language that shines in critical issues such as memory safety, performance and reliability. We joined the Rust Foundation to help contribute towards the growth, advancement and adoption of Rust, and towards sustainable development of open source technologies and developer communities across the world.
This blog is a part of our Rust Nibbles series, where we go over the various Rust libraries we have open-sourced to learn more about what motivated their creation and how one can use them. We hope that this series helps you create amazing projects by using these libraries and encourages you to try them out.