Handling Rust enum variants with kinded crate
Serhii Potapov August 07, 2023 #rust #traits #macro #enumOver the weekend, I delved into crafting a tiny procedural macro library called kinded. The idea behind this venture originated from my need to support another procedural macro library of mine, nutype.
In this article, I will walk you through the concept and application of the kinded
library.
The Use Case: Building a Beverage Selection UI
Imagine you're developing a beverage ordering application. Users can choose from a variety of drinks, some of which might have additional customization options. For instance, you offer various types of coffee and tear, each with different flavors. To create a smooth user experience, you want to present users with a selection of drink categories first and then prompt them for specific details based on their selection.
The Problem
Your Drink
enum captures the different types of beverages available:
However, building the UI becomes a bit tricky. You want to display a list of drink categories to users before they provide additional details for their chosen drink. To do this, you need to extract just the kind of each variant without dealing with the associated data.
Initial solution
So we introduce DrinkKind
type, which is just a plain twin of Drink
without extra data attached to variants:
We may also want to have ability to convert Drink
-> DrinkKind
:
And ability to iterate over all variants of DrinkKind
:
The problem with the solution
The solution above will work. But if you have 20 of such enums, the boilerplate work multiplies.
Also the maintenance cost is doubled: if you want to add a new drink (e.g. Mate
🧉), you'd need extend Drink
and DrinkKind
.
And do not forget to update DrinkKind::all()
implementation! The compiler won't ask you to do it.
Enter kinded
crate
The boilerplate can be eliminated with help of kinded crate and its Kinded
derive macro:
This generates exactly the same code (and a bit more), that wrote manually in the previous step.
Listing drink variants
So now we can list all the possible drink variants as the following:
for drink_kind in all
Output:
TapWater
Coffee
Tea
Fine but TapWater
does not look very human friendly. We'd rather like to see Tap Water
instead.
It's possible to customize implementation of Display
crate for DrinkKind
with display =
option.
So now TapWater
variant is displayed as Tap Water
. At the moment of writing, the library supports 9 different casing strategies like snake_case
, camelCase
, etc.
What about parsing?
Implementation of FromStr
is also generated for free and is capable to parse all possible spelling of the variants.
For example:
let alt_spellings = ;
for alt_spelling in alt_spellings
Closing the Beverage Select UI
Once the user selects a drink category, you can further retrieve the associated data from the original Drink
enum based on the choice:
Conclusion
The kinded
library simplifies the handling of enums with associated data by generating a kind type
that abstracts away the data, making it easier to build user interfaces and handle various enum variants and to write parsers.
To learn more about the kinded
library please check the following links: