Rust Nibbles – Gazebo

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 will cover the cmp module. 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 cmp module contains several utilities that make it easy to compare and test equality.

Compare and equate chains

Implementing PartialOrd for complex objects can require a long series of comparisons.

fn cmp (& self, other: & Self) -> Ordering {match self.field_1.cmp (other.field_1) {Ordering :: Equal => {}, ord => {return ord; }} match self.field_2.cmp (other.field_2) {Ordering :: Equal => {}, ord => {return ord; }} … // repeat for as many fields we need to compare}

The cmp_chain macro allows us to simplify the above in just a few lines:

fn cmp (& self, other: & Self) -> Ordering {cmp_chain! (self.field_1.cmp (other.field_1), self.field_2.cmp (other.field_2), … // repeat for as many fields as we need to compare)}

It also works with result and? in try_cmp

fn try_cmp (& self, other: & self) -> result {cmp_chain! (self.field_1.try_cmp (other.field_1) ?, self.field_2.try_cmp (other.field_2) ?, … // repeat for so many fields that we need to compare)}

eq_chain is the same as cmp_chain, but for equality.

These comparison and equality implementations, while functional, can be tedious to write and maintain. The cmp module intervenes to make this work easier.

PartialEqAny

PartialEqAny was created to allow equality between all types. This is particularly useful to enable equality of features by having features return a token that can be used for comparison. PartialEqAny wraps an object that is PartialEq so that it hides the actual type of the object, which then allows equality between each type but preserves that object’s equality behavior.

As an example, we can have a property

feature MyTrait {… fn eq_token (& self) -> PartialEqAny; }

with multiple implementations of Foo and Bar.

We can derive PartialEq for each respective structure and then provide the implementation

impl MyTrait for Foo {… fn eq_token (& self) -> PartialEqAny {PartialEqAny :: new (self)}}

and the same for Bar. PartialEqAny ensures that equals are only returned if the underlying object is of the same type, and equals according to the equals of the underlying object.

We can then take any instance of dyn MyTrait and get the equality token to compare. It is also possible to implement PartialEq on the dyn feature itself

impl PartialEq for dyn MyTrait {… fn eq (& self, other: & Self) -> bool {self.eq_token () == other.eq_token ()}}

whereby we can use the object characteristic wherever equality is required.

Note that instead of deriving PartialEq for Foo and Bar, we can create the equality token using certain fields of the two structures, which allows for flexible equality behavior for the characteristic.

Maybe Gl

MaybeEq introduces the concept that an object may be PartialEq. Any object that is MaybeEq can be arguments to may_eq (x, y), which returns an optionwhere None indicates no equality and Some indicates equality according to the Boolean value.

We hope this blog helps you understand and use the Cmp module and give you a good look at its features. Look out for our next blog in this series, where we discuss the Cast module, which offers more restrictive alternatives for unsafe conversions.

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
Pavilion variants
Pavilion – AnyLifetime

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.