Rust Nibbles – Gazebo : Variants

This article was written in collaboration with Bob Yang, a software engineer in the Developer Infrastructure Organization at Facebook.

The Rust Gazebo Library contains a collection of proven Rust utilities in the form of stand-alone modules. In this series of blog posts, we’re going to cover some of the modules that make up the Gazebo Library. In today’s blog we go into the module variants. This blog is part of our Rust Nibbles series where we’ll go over the various Rust libraries we’ve made open source to learn more about what motivates their creation and how to use them.

The Gazebo Variants library contains two derived macros and corresponding properties that make working with variants a little easier, clearer and less error-prone.

It is often useful to get the string name of a particular enumeration variant. Let’s take this list as an example:

enum Foo {A, B (String), C {bar: String},}

It is useful to support some operations to get the variant name as “A”, “B”, “C” without printing the debug or display of the data that this variant might contain. The standard derivatives for display and debug do not work because they would include the data as part of the string. So we have to implement such a function manually:

impl Foo {fn variant_name (& self) -> String {match self {A => “A” .to_owned (), B (_) => “B” .to_owned (), C {..} => “C” .to_owned (),}}}

Writing this code manually poses a few problems:

  • It is an unnecessary boiler plate and very tedious for lists that have a large number of variants.
  • It is error-prone to accidentally misspellings between the actual variant and the returned string.
  • Adding, removing or renaming variants in the enumeration now requires changing multiple plates.

With Gazebo you can derive the variant names like this

Use Pavilion :: variants :: VariantName; #[derive(VariantName)]
List Foo {…}

And you can simply call anywhere that needs the name

Use Pavilion :: variants :: VariantName; let name = foo.variant_name ();

The other derivation that Variants offers is to unpack enumerations. It is a common pattern to want to optionally unpack a certain variant of the enumeration.

match foo {B (x) => Some (x), _ => None}

While this code isn’t bad, this pattern appears frequently, and possibly for many different variations of the same enumeration.

Use pavilion :: prelude :: *; let ys = xs.map (| x | x.abs ());

By doing

#[derive(UnpackVariants)]
List Foo {…}

The code can be simplified to foo.unpack_b () or one of its other flavors. It even works for named variants, which are automatically extracted into a tuple ordered according to the definition.

We hope this blog helps you understand the Variants module, how to use it, and gives you a good look at its features. Look out for our next blog in this series where we discuss the AnyLifetime trait, which extends the standard Any trait to types with lifetimes.

Check out our previous blogs in the Gazebo series to learn more about the various features the Gazebo Library has to offer –
Pavilion – Prelude
Pavilion – dupe

About the Rust Nibbles series

At Facebook, we believe that Rust is a stellar language that shines on critical issues like storage security, performance, and reliability. We have joined the Rust Foundation to contribute to the growth, advancement, and adoption of Rust, and the sustainable development of open source technologies and developer communities around the world.

This blog is part of our Rust Nibbles series where we’ll go over the various Rust libraries we’ve made open source to learn more about what motivates their creation and how to use them. We hope this series helps you create amazing projects using these libraries and encourages you to try them out.

To learn more about Facebook Open Source, visit our open source site, subscribe to our YouTube channel, or follow us on Twitter and Facebook.

Comments are closed.