Back to News for Developers

Rust Nibbles - Gazebo: Variants

July 13, 2021ByNavyata Bawa

This article was written in collaboration with Bob Yang, a Software Engineer in the Developer Infrastructure organization at Facebook.

The Rust library Gazebo contains a collection of well-tested Rust utilities in the form of standalone modules. In this series of blog posts, we will cover some of the modules that make up the Gazebo library. In today’s blog, we will cover the module variants. 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.

The Gazebo Variants library contains two derive macros and corresponding traits that makes working with variants a little easier, concise, and less error-prone.

It’s often useful to obtain the String name of a particular enum variant. Let’s take this enum as an example:

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

        

It’s useful to support some operation to get the name of the variant as “A”, “B”, “C”, without printing the debug or display of the data that variant might hold. The standard derives for Display and Debug will not work as they would include the data as part of the String. Therefore, we must manually implement such a function:

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

        

Having to write this code manually poses a few problems:

  • It’s unnecessary boilerplate, and very tedious with enums that have a large number of variants.
  • It’s error prone to have accidental mismatch of typos between the actual variant and the string returned.
  • Adding, removing, or renaming variants on the enum now requires multiple plates to modify.

With Gazebo, you can derive the variant names as so

use gazebo::variants::VariantName;
#[derive(VariantName)]
enum Foo {
  ...
}

And anywhere that needs the name can simply call

use gazebo::variants::VariantName;
let name = foo.variant_name();
        

The other derive that Variants provide is to unpack enums. It’s a common pattern to want to unpack a specific variant of the enum as an option.

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

While this code isn’t bad, this pattern crops up a lot, and potentially for a lot of different variants of the same enum. By having

#[derive(UnpackVariants)]
enum Foo {
  ...
}
  
        

The code can be simplified to

foo.unpack_b()
          

or any of its other variants. It even works for named variants, which is automatically unpacked into a tuple ordered by the definition.

We hope that this blog helps you understand the Variants 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 AnyLifetime trait, which extends the standard Any trait to types with lifetimes.

Be sure to check out our previous blogs in the Gazebo series to learn more about the various features the Gazebo library has to offer -
Gazebo - Prelude
Gazebo - Dupe

About the Rust Nibbles series

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.

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